1、赋值发生于赋值时,除此之外,遇到的所有其他的复制情形均为初始化,包括声明、函数返回、参数传递以及捕获异常中的初始化。
对于内建类型来说,赋值和初始化的操作区别不明显,只是简单地复制一些位而已。
但对于用户自定义类型来说截然不同。考虑如下简单的非标准字符串类:
class String {
public:
String (const char *init ); //故意不标为explicit
~String( );
String(const String &that);
String &operator = (const String &that);
String &operator = (const char *str);
void swap( String &that );
friend const String operator + ( const String &, const String & ); //用于连接字符串
friend bool operator < ( const String &, const String & );
//......
private:
String ( const char *, const char*); //计算性的构造函数
char *s_
};
2、采用字符串初始化一个string对象和简单,先分配一个足够大的缓冲区,用于容纳该字符串的复制,然后执行复制动作:
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_ = tmp;
return *this;
}
3、对于String类型来说,String现有的字符缓冲区在被附加上一个新的字符缓冲区之前必须被释放掉。
由于一个正当的赋值操作会清掉左边的实参,因此永远都不应该对一个为初始化的存储区执行用户自定义赋值操作:
String *names = statoc_cast<String *> (::operator new( BUFSIZ));
names[0] = "Sakamoto"; //delete[ ] 未被初始化的names!
names指向为初始化的存储区,因为我们调用了operator new,从而避免了通过String的默认构造函数执行的隐式初始化动作,因此names指向一块填充着随机位的内存。