References:
先来个区别说明:赋值操作是在两个已经存在的对象间进行的,而初始化是要创建一个新的对象,并且其初值来源于另一个已存在的对象。编译器会区别这两种情 况,赋值的时候调用重载的赋值运算符,初始化的时候调用拷贝构造函数。如果类中没有拷贝构造函数,则编译器会提供一个默认的。这个默认的拷贝构造函数只是 简单地复制类中的每个成员。 下面看例子。
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语言中的初始化,都是用花括号进行,简单美观:struct Point point = { 2 , 3 };
struct Point arrPoint[] =
{
{ 2 , 3 },
{ 4 , 5 },
{ 6 , 7 }
};
C++自然也兼容了C语言的初始化机制。然而,C++的Class乃至STL都不支持。它们要用不同的方式来初始化, 甚至根本不能够直接初始化, 只能使用运行时的赋值。
比如Class:
{
public :
int Age;
int Value;
private :
int Level;
};
Param param = { 2 , 3 }; // ERROR
Param param = { 2 , 3 , 4 }; // ERROR
{
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 * p2 = new Param();
再比如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库,至少现在可以初始化了:
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();
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]
C++0x已确定提供与C一致的初始化功能。 Initialer lists Initializer Lists for Standard Containers Initializer lists WP wording 等草案就是为了这个目的服务的。
如果使用C++0x,那么程序的初始化将变得清晰和一致:
// 或
complex < double > z { 1 , 2 };
// 初始化中,有等号和无等号都是允许的,下同。
z += { 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++欠了十多年的债吧。