参考:Effective C++以及http://www.cnblogs.com/dahai/archive/2011/04/11/2012519.html
C++默认的赋值操作是按成员赋值(包括指针,嵌套的类成员等)
如果类成员都为值类型时,工作良好;
但特殊情况下,这种操作往往会有问题。
下面例子是类成员包含指针成员时,使用默认的赋值操作时,导致了内存被重复释放的问题
代码如下:
#include "stdafx.h" #include <string> using namespace std; class A { private: char *p; size_t nSize; public: A(const string &str); ~A(); }; ... int _tmain(int argc, _TCHAR* argv[]) { A obj1("hello"); A obj2("world"); //赋值操作 obj2 = obj1; system("pause"); return 0; }运行会出错!
原因是:采用默认的赋值操作后,obj1.p和obj2.p的成员变量p都指向了同一块内存,这样析构时就对同一块内存释放了两次。
我们赋值的真正意思可能是,两个对象各有自己的一块内存,互不相干,只是复制其中的内容。这时候就需要重载赋值操作符operator=()了。
正确的做法:
#include <string.h> class A { private: char * m_pointer; size_t m_nSize; public: //重载赋值操作符(默认的"="会使类成员指针和返回对象中的成员指针指向同一地址) A& operator=(const A &a); public: A(const char * cStr, const int strLen); ~A(); }; A::A(const char * cStr, const int strLen) { p = new char[strLen + 1]; memset(p, 0, strLen+1); strcpy(p, cStr); nSize=strLen; } A::~A() { delete[] p; } //此做法是Effective C++推荐的做法 inline A& A::operator=(const A &a) { char * tempPointer=a.p; //即时new操作有异常而返回,p也会指向原地址(切记) this->p = new char[a.nSize + 1]; strcpy(this->p, a.p); delete[] tempPointer; return * this; } int main() { A obj1("hello", strlen("hello")); A obj2("world", strlen("world")); //赋值操作(obj2调用operator=()方法) obj2 = obj1; return 0; }
1> obj2=obj1; 实际上是由obj2调用operator=()方法,所以返回值为:*this
2> 在operator=()方法中,由于参数也是A类型,所以可以访问其私有成员变量;
3> 在operator=()方法中,this->p=new char[]中,如果new操作失败,则this->p仍然会指向原地址;
4> 若不希望用户对该类对象进行赋值操作,则可以重载赋值操作符为private;
5> 返回类型为:A &,即引用;
返回引用类型,个人感觉应该是基于如下两个原因:
(1) obj2调用operator=()方法,其不用担心声明周期的问题;
(2) 如果返回类型是值类型,而不是引用的话,则现在的obj2是(原obj2,即调用operator()=的obj2,在重新赋值后)的一个复制品,也就是返回的obj2和调用opertor=()的obj2,其p都指向了同一块内存空间;从而导致重复释放同一片内存空间的错误!