2017-07-28 47 views
-2

說我有一個簡單的類是這樣的:待辦事項構造對象分配內存泄漏


class MyObj 
{ 
char* myPtr; 
public: 
    MyObj() 
    { 
     myPtr = malloc(30); 
    } 
    ~MyObj() 
    { 
     free(myPtr); 
    } 
} 

class TestObject 
{ 
    MyObj _myObj; 

public: 
    TestObject(MyObj myObj) 
    { 
     _myObj = myObj; 
    } 
}; 

這是否泄漏內存?我的推理是,構造函數運行時TestObject已經包含了一個MyObj實例,所以在內存被釋放之前,這並不能消除myPtr?分配給本地對象是否調用被替換的對象的析構函數?如果編譯器直接在構造函數中賦值,編譯器是否會優化對象實例變量的賦值?我來自C#,其中一個對象不會通過聲明一個引用類型變量而自動初始化,所以這有點讓我困惑。

謝謝!

+3

「這是否泄漏記憶?」你的C++教科書對此有何評論? –

+6

這兩個泄漏內存*和*最終雙釋放內存。總之,你會被迫使這個*更多*錯誤比現在。 – WhozCraig

+0

爲了不存在泄漏問題或雙重問題,您需要遵循[rule-of-5](http://en.cppreference.com/w/cpp/language/rule_of_three)。或者走最佳路線並使用'std :: unique_ptr' – Justin

回答

3

這是否泄漏記憶?

myObj的分配將調用默認的複製分配操作符,因爲您沒有提供覆蓋。因此,會執行逐個成員的副本,並且分配目標的myPtr實例將被來自分配源的myPtr實例覆蓋。這裏介紹兩個問題,違反了Rule of Three/Five/Zero的一個或多個部件時,經常遇到:

  1. 您失去從分配的目標原來myPtr內容。因此,該指針唯一引用的原始內存被泄漏。
  2. 您現在的分享相同的指針值在兩個myPtr成員:來源分配操作的目標。

後者特別令人不安,因爲myObjTestObject構造函數中完成賦值後立即離開範圍。在這樣做的時候,myObj將被銷燬,並且與此同時,它被釋放了myPtr。此外,myObj通過到該構造函數,而不是引用,所以隱式副本已經可能發生(由於右值移動語義,缺乏副本)。因此, MyObj對象很可能被吊裝myPtr所有引用相同的內存,並儘快發佈一個它,其餘的都在不知不覺中提升晃來晃去指針。任何解引用或這些指針的調用將調用未定義的行爲

給本地對象調用分配對象的析構函數嗎?

只有調用了析構函數才能與它們同名。也就是說,只有當一個對象被破壞被破壞時(手動調用析構函數進行放置 - 新的語義)時纔會調用它們。除非引入臨時對象,否則複製分配不會執行該操作,而代碼中則不是這種情況。

如果編譯器直接在構造函數中賦值,編譯器是否會優化對象實例變量的賦值?

不,但member initialization list可以在這方面提供幫助。


現代C++編程技術經常使用RAII來完成你彷彿是試圖以多種方式,這取決於你真正想要達到的目標。

唯一數據每個實例

如果目標是每個實例獨有的動態數據,您可與std::vector<char>,或者乾脆std::string容易做到這一點,取決於底層需求。兩者都是RAII數據類型,通常對於動態內存管理需求而言是充足的。

class MyObj 
{ 
    std::vector<char> myData; 
public: 
    MyObj() : myData(30) 
    { 
    } 
} 

class TestObject 
{ 
    MyObj _myObj; 

public: 
    TestObject(MyObj myObj) 
     : _myObj(std::move(myObj)) 
    { 
    } 
}; 

這消除MyObj需要析構函數,並利用移動語義以及在TestObject構造上述成員初始化列表。 MyObj的所有實例都將提升一個不同的向量charMyObjTestObject的所有分配操作都使用默認實現。

分配共享內存

不太可能你想要這個,但它是沒有最不具有可行性:

class MyObj 
{ 
    std::shared_ptr<char> myPtr; 
public: 
    MyObj() : myPtr(new char[30]) 
    { 
    } 
}; 

class TestObject 
{ 
    MyObj _myObj; 

public: 
    TestObject(MyObj myObj) 
     : _myObj(std::move(myObj)) 
    { 
    } 
}; 

類似的代碼,但不同的成員類型。現在myPtrshared pointerchar的數組。任何分配給不同的myPtr都將加入共享列表。簡而言之,分配意味着兩個對象都參考相同的數據,並且引用計數可以確保最後一個人能夠清除混亂。

注意:使用像這樣的共享指針可能導致內存泄漏,因爲new可能會成功,但共享指針的共享數據塊可能會引發異常。這是在C++ 17, 其中std::make_shared支持數組分配


這些做什麼,你可能會嘗試完成的只是一些方法解決。我鼓勵您在所提供的鏈接和本網站上閱讀關於Rule of Three/Five/Zero和約RAII的概念。有很多例子可能會回答您可能遇到的更多問題。

+0

謝謝!超級有用。 –