从赋值到初始化

时间:2021-08-24 04:20:26

   C语言确实很优雅,整个语言的设计简洁一致。而在C++中,有一个让人诟病的问题就是变量初始化的不一致性。
   C语言中的初始化,都是用花括号进行,简单美观:

int  array[]  =  { 1 , 2 , 3 , 4 , 5 };
struct  Point point  =  { 2 3 };
struct  Point arrPoint[]  =  
{
  {
2 , 3 },
  {
4 , 5 },
  {
6 , 7 }
};

   C++自然也兼容了C语言的初始化机制。然而,C++的Class乃至STL都不支持。它们要用不同的方式来初始化,甚至根本不能够直接初始化, 只能使用运行时的赋值。
   比如Class:
class  Param
{
public :
  
int  Age;
  
int  Value;
private :
  
int  Level;
};

Param param 
=  { 2 , 3 };  //  ERROR
Param param  =  { 2 , 3 , 4 };  // ERROR
   无法初始化。而如果不初始化的话,所有的成员而处于无*状态,这显然很不让人放心。于是,C++提供了专门用于Class的初始化方式--构造函数:
class  Param
{
public :
  Param(
int  x,  int  y)
    : x_(x), y_(y)
  {}
  Param()
    : x_(
0 ), y_( 0 )
  {}
private :
  
int  x_, y_;
};

Param param(
1 , 2 );
//
Param param;
   有了构造函数,可以在构造函数的初始化列表中对成员进行初始化。可是很明显,这里头还是有一个陷阱,默认构造初始化和非默认构造初始化的调用方式是不一致的。默认构造函数不能用括号来调用,否则编译器将会发疯:
Param param();
   它会把上面的语句看成是函数声明,而后面调用的时候就会出错,而错误信息可能会让你抓狂一下。但是这样也就算了,偏偏new 可以接受有括号和没括号两种写法:
从赋值到初始化Param *  p1  =  new  Param;
从赋值到初始化Param
*  p2  =  new  Param();
   再来说说初始化列表。初始化列表,事实上,也只能支持简单的标量类型,诸如int,bool,指针之类的;复杂点的,如数组、结构,不好意思,不支持--只能在构造函数体中进行赋值。还有一个很迷糊初学者的问题是,成员初始化的顺序仅依赖于成员定义的顺序,而不是初始化列表中的顺序。

   再比如STL容器,这下好象更惨,连构造函数都帮不上忙了,除了初始化一个空的容器,或是复制一下别的容器,我们只能做用默认构造函数进行初始化。我们拿数组和vecotr做个比较:
//  数组
int  arr[] = { 1 , 2 , 3 , 4 };
//  vector
vector < int >  iarr;
//  必须在某个函数中赋初值
void  init()
{
  
for ( int  i  =  1 ; i  <=  4 ++ i) 
    iarr.push_back(i);
}

   再复杂一点的数据结构,那单单赋值程序就要写上老长,而且还不好看。还要记得调用。这对于仅仅是简单的设置一些初值的用途来说,太过于烦琐。

   横向比较,这次好象C++还不会太落伍,只有C和动态语言提供了初始化特性,其它支持OO高级语言好象都是学C++的。如Java,C#(注C#3.0开始提供初始化功能)...
   
   C++能不能做到简洁一致的实始化呢?
   Boost的assign库做了许多有益的工作。使用assign库,至少现在可以初始化了:
从赋值到初始化vector < int >  arr  =  list_of( 1 )( 2 )( 3 )( 4 );   
从赋值到初始化
从赋值到初始化typedef boost::tuple
< int ,std:: string , int >  tuple;
从赋值到初始化vector
< tuple >  v  =  tuple_list_of(  1 " foo " 2  )(  3 " bar " 4  );
从赋值到初始化
从赋值到初始化map
< int , int >  next  =  map_list_of( 1 , 2 )( 2 , 3 )( 3 , 4 )( 4 , 5 )( 5 , 6 );
从赋值到初始化
从赋值到初始化stack
< string >  names  =  list_of(  " Mr. Foo "  )(  " Mr. Bar " )(  " Mrs. FooBar "  ).to_adapter();
   如果是赋值,也可以简略很多:
从赋值到初始化vector < int >  v;
从赋值到初始化
+=  1 , 2 , 3 ,repeat( 10 , 4 ), 5 , 6 , 7 , 8 , 9 ;
从赋值到初始化
//  v = [1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,7,8,9]
 不过,也仅能如此了。assign经过许多努力,也仅能支持容器的初始化,而且还不够漂亮。

   C++0x已确定提供与C一致的初始化功能。 Initialer lists  Initializer Lists for Standard Containers  Initializer lists WPwording 等草案就是为了这个目的服务的。
   如果使用C++0x,那么程序的初始化将变得清晰和一致:
complex < double >  z  =  { 1 , 2 }; 
//
complex < double >  z { 1 , 2 }; 
//  初始化中,有等号和无等号都是允许的,下同。
+=  { 2 , 3 };

int  a  =  { 1 }; 

new  vector < string > { " once " " upon " " a " " time " }; 

f( {
" Nicholas " " Annemarie " } );  //  参数是两个元素的列表

return  {  " Norah "  };  //  返回只有一个元素的列表
 
int *  e {};   //  初始化为0或NULL指针

map
< string , int >  anim  =  

  {
" bear " , 4 }, 
  {
" cassovary " , 2 }, 
  {
" tiger " , 7
}; 

   这好象是C++欠了十多年的债吧。