(轉)C++初始化與賦值

來源:http://www.cnblogs.com/chio/archive/2008/10/06/1305145.htmlhtml

先來個區別說明:賦值操做是在兩個已經存在的對象間進行的,而初始化是要建立一個新的對象,而且其初值來源於另外一個已存在的對象。編譯器會區別這兩種情 況,賦值的時候調用重載的賦值運算符,初始化的時候調用拷貝構造函數。若是類中沒有拷貝構造函數,則編譯器會提供一個默認的。這個默認的拷貝構造函數只是 簡單地複製類中的每一個成員。 下面看例子。   

c++中初始化和賦值操做差異是很大的。  
對於基本數據類型差異不大:  
好比:  
int a = 12; // initialization, copy 0X000C to a  
a = 12; // assignment, copy 0X000C to a  
可是對用戶自定義的數據類型好比String 初始化和賦值就差異很大:  
class String ...{  
 public:  
 String( const char *init ); // intentionally not explicit!  
 ~String();  
 String( const String &that );  
 String &operator =( const String &that );  
 String &operator =( const char *str );  
 void swap( String &that );  
 friend const String // concatenate  
 operator +( const String &, const String & );  
 friend bool operator <( const String &, const String & );  
 //...  
 private:  
 String( const char *, const char * ); // computational  
 char *s_;  
};  
初始化的構造過程比較簡單:先分配一個足夠大的空間而後填充上數據:  
String::String( const char *init ) ...{  
 if( !init ) init = """";  
 s_ = new char[ strlen(init)+1 ];  
 strcpy( s_, init );  
}  
析構過程更簡單:  
String::~String() ...{ delete [] s_; }  

可是若是賦值操做就複雜多了:  
String &String::operator =( const char *str ) ...{  
  
 if( !str ) str = """";  
  
 char *tmp = strcpy( new char[ strlen(str)+1 ], str );  // 多了中間變量  
  
 delete [] s_; // 多了刪除s_;  
 s_ = tmp;   // 多一個賦值操做!如今是指向字符的指針,若是是個大對象,效率的差異可想而知.  
  
 return *this;  
}c++

 C++初始化語法的不一致性:數組

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:this

class  Param
{
public :
  
int  Age;
  
int  Value;
private :
  
int  Level;
};

Param param 
=  { 2 , 3 };  //  ERROR
Param param  =  { 2 , 3 , 4 };  // ERROR

   沒法初始化。而若是不初始化的話,全部的成員而處於無政府狀態,這顯然很不讓人放心。因而,C++提供了專門用於Class的初始化方式--構造函數:spa

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作個比較:htm

//  數組
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 WP wording 等草案就是爲了這個目的服務的。
   若是使用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++欠了十多年的債吧。

相關文章
相關標籤/搜索