需要析構(gòu)函數(shù)的類也需要拷貝和賦值操作
class HasPtr
{
public:
HasPtr(const std::string &s = std::string())
: ps(new std::string(s))
, i(0)
{}
~HasPtr() { delete ps; }
// ...
};
此時棘脐,意味著我們在使用合成的拷貝構(gòu)造函數(shù)和拷貝賦值運(yùn)算符昏滴。這些函數(shù)簡單拷貝指針成員吭露,這意味著多個 HasPtr 對象可能指向相同的內(nèi)存:
HasPtr f(HasPtr hp) {
HasPtr ret = hp;
return ret;
}
當(dāng) f 返回時暇屋,hp 和 ret 都被銷毀煞抬,在兩個對象上都會調(diào)用 HasPtr 的析構(gòu)函數(shù)低飒。此析構(gòu)函數(shù)會 delete ret 和 hp 中的指針成員霹崎。但這兩個對象包含相同的指針值胯陋。此代碼會導(dǎo)致此指針被 delete 兩次,者顯然是一個錯誤扒磁。將要發(fā)生什么是未定義的庆揪。
此外,f 的調(diào)用者還會使用傳遞給 f 的對象:
HasPtr p("some values");
f(p); // 當(dāng) f 結(jié)束時妨托,p.ps 指向的內(nèi)存被釋放
HasPtr q(p); // 現(xiàn)在 p 和 q 都指向無效內(nèi)存
p(以及 q)指向的內(nèi)存不再有效嚷硫,在 hp(或 ret!)銷毀時它就被歸還給系統(tǒng)了始鱼。
綜上所述仔掸,如果一個類需要自定義析構(gòu)函數(shù),幾乎可以肯定它也需要自定義拷貝賦值運(yùn)算符和拷貝構(gòu)造函數(shù)医清。
需要拷貝操作的類也需要賦值操作起暮,反之亦然
假設(shè)一個類為每個對象分配一個獨(dú)有的、唯一的序號会烙。這個類需要一個拷貝構(gòu)造函數(shù)為每個新創(chuàng)建的對象生成一個新的负懦、獨(dú)一無二的序號。除此之外柏腻,這個拷貝構(gòu)造函數(shù)從給定對象拷貝所有其他數(shù)據(jù)成員纸厉。這個類還需要自定義拷貝賦值運(yùn)算符來避免將序號賦予目的對象。但是五嫂,這個類不需要自定義析構(gòu)函數(shù)颗品。
這個例子說明:如果一個類需要一個拷貝構(gòu)造函數(shù),幾乎可以肯定它也需要一個拷貝賦值運(yùn)算符沃缘。反之亦然——如果一個類需要一個拷貝賦值運(yùn)算符躯枢,幾乎可以肯定它也需要一個拷貝構(gòu)造函數(shù)。然而槐臀,無論是需要拷貝構(gòu)造函數(shù)還是需要拷貝賦值運(yùn)算符都不一定需要析構(gòu)函數(shù)锄蹂。