什么是三法则
如果需要析构函数,则一定需要拷贝构造函数和拷贝赋值操作符。
什么是五法则
如果需要析构函数,则一定需要拷贝构造函数和拷贝赋值操作符。在较新的 C++11 标准中,为了支持移动语义,又增加了移动构造函数和移动赋值运算符,这样共有五个特殊的成员函数,所以又称为“C++五法则”;
原因:
类中出现了指针类型的成员。有指针类型的成员,我们必须防止浅拷贝问题,所以,一定需要拷贝构造函数和赋值操作符,这两个函数是防止浅拷贝问题所必须的。
一个对象拥有额外的资源(指针指向的内存),但另一个对象使用合成的拷贝构造函数也同时拥有这块资源。当一方对象被销毁后,析构函数释放了资源,这时另一个对象便失去了这块资源(但程序员还不知道)。
class HasPtr{public:HasPtr(const std::string& s = std::string()) :ps(new std::string(s)), i(0) {}//HasPtr(const HasPtr& hasPtr);//HasPtr& operator=(const HasPtr& hasPtr);~HasPtr() { delete ps; };private:std::string* ps;int i;};HasPtr f(HasPtr hp) // 使用了合成拷贝构造函数,使得hp.ps 和 p.ps 指向相同内存{HasPtr ret = hp; // 使用了合成拷贝构造函数,使得ret.ps 和 hp.ps 指向相同内存return ret; // retrurn 之后,ret和hp 会被释放资源,调用析构函数 析构函数会delete ps 导致p.ps 的内存被释放。}HasPtr p("some value");f(p); // 当f结束时,p.ps 指向的内存被释放HasPtr q(p); // p和q都指向无效内存
如果一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝运算符
需要拷贝操作的类也需要赋值操作,反之亦然,但不一定意味着需要析构函数 与三之法则不同的是,不提供移动构造函数和移动赋值运算符通常不是错误,但会导致失去优化机会。