2014-10-02 192 views
2

我今天看到了一個我不熟悉的new的用法。這是否會造成內存泄漏?

{ 
    string * test = new string("bye"); 
    new (test) string("hello"); 
    cout << *test << endl; //prints "hello" 

    delete test; 
} 

這似乎像它應該在第一,但如果我嘗試和「記住」的test初始值,它看起來像記憶被重新分配:

string * test = new string("bye"); 
string * test2 = test; 
new (test) string("hello"); 
cout << *test << endl; //prints "hello" 
cout << *test2 << endl; //also prints "hello" 

這是怎麼回事?

+0

我不確定你試圖用第二個例子來證明什麼。爲什麼*不會*'cout << * test2'打印你好? – meagar 2014-10-02 02:02:08

+0

放置新的,是的,它泄漏,因爲原始對象的析構函數沒有運行。 – mythagel 2014-10-02 02:02:21

+0

@megar,因爲我已將'test2'分配給'test'的原始值。如果新內存由第二個'new'語句分配,'test'的值應該改變。但事實並非如此。 – 2014-10-02 02:04:05

回答

2

確實存在潛在的內存泄漏,但不是因爲您可能會考慮的原因,有兩個new和只有一個delete。這其實很好。

問題是第一個字符串的析構函數從未運行。它分配的任何內部存儲器都不會被釋放。

要解釋,第二個new是所謂的放置new。這是在內存中調用已分配的構造函數的一種方法。 new (test) string("hello")的效果是它會覆蓋第一個字符串("bye")和另一個字符串("hello") )。展示位置new不會分配更多內存。它只是在現有內存區域上運行string::string(const char *)構造函數。

這就是爲什麼程序打印hello兩次。 testtest2都指向相同的字符串,因此當您覆蓋該字符串時,變化將顯示在兩個變量中。變量本身沒有改變,但它們指向的對象具有。

+0

nitpick:如果接受'std :: string *'的operator new'有重載,則不一定返回該指針。說明提供不完整代碼的危險性(正如OP所做的那樣),以及教授具體內容的危險性(OP可能後來遇到區分很重要的代碼)。 – 2014-10-02 02:13:30

+0

是的,你是對的。我已經提出了一個說明,我的答案因教學目的而過於簡化。 – 2014-10-02 02:20:52

1

您正在查看的內容稱爲placement new。它調用已分配內存塊的構造函數。

由於原始對象從未被銷燬,它肯定會導致內存泄漏。如果沒有,這可能是因爲短字符串包含在對象本身中,並且不會導致字符串緩衝區的分配。

2

是的,你有(*可能)內存泄漏。不,檢查代碼沒有證明。它演示了兩個指針都指向同一個對象。


要理解這一點,注意,std::string一般存儲文本的其他地方,因爲它動態分配的緩衝區。

因此,當你new一個std::string,至少有兩個動態分配:

  • std::string對象本身的動態分配。
  • 該對象的動態分配字符串緩衝區。

內存泄漏與緩衝區有關,由於未運行第一個std::string對象的析構函數,因此緩衝區未釋放。


*)「 」可能的,而不是某些因爲std::string,而相比之下,一個std::vector,可以採用在那裏將數據直接存儲短緩衝器優化。