![](/img/trans.png)
[英]In a C++ library, who should delete the pointers, the user or the library?
[英]C++ Pointer data members: Who should delete them?
所以說我有這樣一個類:
class A {
public:
A( SomeHugeClass* huge_object)
: m_huge_object(huge_object) {}
private:
SomeHugeClass* m_huge_object;
};
如果有人使用這樣的構造函數:
A* foo = new A(new SomeHugeClass());
誰負責在構造函數中新建的對象上調用delete? 在這種情況下,調用A構造函數的范圍只能刪除foo,因為SomeHugeClass是匿名的。
但是,如果有人像這樣使用構造函數呢?
SomeHugeClass* hugeObj = new SomeHugeClass();
A* foo = new A(hugeObj);
然后,調用者可以在某個時候調用delete hugeObj,對嗎?
A的這種實現是否會破壞內存?
我正在研究一個以這種方式完成大量對象組合的項目,盡管我希望使用智能指針,但我必須與項目負責人討論如何更改舊代碼以便在我可以之前利用它。
我盡可能地嘗試遵循這個簡單的規則:調用new
應該調用delete
。 否則,代碼很快就會變得太亂,無法跟蹤刪除的內容和不刪除的內容。
在你的情況下,如果A :: A收到指針,它不能刪除它。 想想這個簡單的案例:
SomeHugeClass* hugeObj = new SomeHugeClass();
A * a1 = new A(hugeObj);
A * a2 = new A(hugeObj);
A類不知道還有誰在使用該指針!
如果你想要A類來處理指針,它應該自己創建它。
當然,你可以處理這兩種情況,但這可能是一種矯枉過正,如下所示:
A::A() : own_huge_object(true) {
m_huge_object = new SomeHugeClass();
}
A::A(SomeHugeClass * huge_object ) : own_huge_object(false) {
m_huge_object = huge_object;
}
A::~A() { if(own_huge_object) delete m_huge_object; }
在您的示例中,調用者應該負責刪除huge_object
因為構造函數可能拋出異常,並且不會調用A
析構函數。 而且你的實現有內存泄漏,因為現在沒有人調用delete
。
您可以使用shared_ptr
,如下所示:
class A {
public:
A( shared_ptr<SomeHugeClass> huge_object)
: m_huge_object(huge_object) {}
private:
shared_ptr<SomeHugeClass> m_huge_object;
};
在這種情況下,您不應該關心刪除SomeHugeClass
。
為了這一行在下面
A* foo = new A(new SomeHugeClass());
不要導致內存泄漏,你可以確保在A類的析構函數中釋放m_huge_object指向的內存。
A類定義可能如下所示:
class A {
public:
A(SomeHugeClass* huge_object)
: m_huge_object(huge_object) {}
~A() { delete m_huge_object; }
private:
SomeHugeClass* m_huge_object;
};
我不喜歡上面的內容是我更喜歡分配內存的人也應該是負責釋放內存的人。 此外,還有基里爾指出的問題。 所以保持你對A類的定義,代碼可以簡單如下:
SomeHugeClass* hugeObj = new SomeHugeClass();
A* foo = new A(hugeObj);
//some code
delete hugeObj;
delete foo;
這更像是一個設計問題。 傳統上,當您將非常量指針傳遞給構造函數時,該對象應該釋放指針。 如果您打算保留副本,請傳遞const引用。
另一種設計是這樣的:SomeHugeClass通常不是那么大(例如指針),但擁有大量的內存:
class A
{
SomeHugeClass m_;
public:
A(SomeHugeClass x) { m_.swap(x); }
};
如果SomeHugeClass實現了有效的交換(交換指針),那么這種設計是可行的。 構造x
在將其交換為m_
之前生成x
的副本,如果將臨時對象傳遞給構造函數,則編譯器可能會(並且通常將)刪除該副本。
注意,someHugeClass可以在這里替換為smart_pointer<SomeHugeClass>
,當你將smart_pointer(new SomeHugeClass())傳遞給構造函數時,它會給你所需的語義,因為它是臨時的。
編輯(為清晰起見......):最終代碼可能看起來像
class A
{
smart_ptr<SHC> m_;
public:
A(smart_ptr<SHC> x) { m_.swap(x); }
};
當你調用A(new SHC(...))
沒有所需的行為(沒有復制,當A被破壞時刪除),當你調用A(smart_ptr<SHC>(a))
(執行a
副本A(smart_ptr<SHC>(a))
,當A被破壞時釋放)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.