在赋值运算符中要特别注意可能出现别名的情况,其理由基于两点。其中之一是效率。如果可以在赋值运算符函数体的首部检测到是给自己赋值,就可以立即返回,从而可以节省大量的工作,否则必须去实现整个赋值操作。
另一个更重要的原因是保证正确性。一个赋值运算符必须首先释放掉一个对象的资源(去掉旧值),然后根据新值分配新的资源。在自己给自己赋值的情况下,释放旧的资源将是灾难性的,因为在分配新的资源时会需要旧的资源。
看看下面string对象的赋值,赋值运算符没有对给自己赋值的情况进行检查:
class string { public: string(const char *value); // 函数定义参见条款11 // ~string(); // 函数定义参见条款11 // ... string& operator=(const string& rhs); private: char *data; }; // 忽略了给自己赋值的情况 // 的赋值运算符 string& string::operator=(const string& rhs) { delete [] data; // delete old memory // 分配新内存,将rhs的值拷贝给它 data = new char[strlen(rhs.data) + 1]; strcpy(data, rhs.data); return *this; // see item 15 }
现在可以知道,解决问题的方案是对可能发生的自己给自己赋值的情况先进行检查,如果有这种情况就立即返回。不幸的是,这种检查说起来容易做起来难,因为你必须定义两个对象怎么样才算是“相同”的。
一个确定对象身份是否相同的方法是用内存地址。采用这个定义,两个对象当且仅当它们具有相同的地址时才是相同的。这个定义在c++程序中运用更广泛,可能是因为它很容易实现而且计算很快,而采用值相等的定义则不一定总具有这两个优点。采用地址相等的定义,一个普通的赋值运算符看起来象这样:
c& c::operator=(const c& rhs) { // 检查对自己赋值的情况 if (this == &rhs) return *this; ... }
条款十七: 在operator=中检查给自己赋值的情况,布布扣,bubuko.com
原文:http://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3904635.html