2017-07-19 29 views
0

我正在用C++實現C-API,並且在接口處我必須將C++類似的數據結構轉換爲C-API的現有數據結構。我負責數據結構的內存,所以我可以使用新的和刪除,但從我的理解下面的C++ 11代碼可以有內存泄漏(這只是一個虛擬的例子):如何通過連續使用'new'來防止分配失敗時的內存泄漏

#include <string> 
#include <new> 

struct container { 
    char *message; 
}; 

/* converts an std::string to a C data structure */ 
container *create_container(const std::string& message) { 
    container *c = nullptr; 
    try { 
     container *c = new container; 
     c->message = new char[message.length() + 1]; 
     message.copy(c->message, message.length()); 
     c->message[message.length()] = '\0'; 
    } catch (std::bad_alloc exception) { 
     return nullptr; 
    } 

    return c; 
} 

void destroy_container(container *c) { 
    if (c != nullptr) { 
     if (c->message != nullptr) { 
      delete[] c->message; 
     } 
     delete c; 
    } 
} 

int main(void) { 
    container *c = create_container("message"); 
    destroy_container(c); 

    return 0; 
} 

如果c->message的分配失敗,它會泄漏c

所以我的問題:我該如何理想地處理這種情況?

我想出什麼了到目前爲止:

/* ... */ 
    } catch (std::bad_alloc exception) { 
     if (c != nullptr) { 
      delete c; 
     } 
     return nullptr; 
    } 
    /* ... */ 

有沒有更好的方法在C++中做到這一點?

也有可能發生在C++中只有記憶與newdelete管理,你碰巧在同一try塊捕獲std::bad_alloc使用new兩次應用此問題。

這可能是使用智能指針或其他方式解決?

+0

'auto c = std :: make_unique (); ...;返回c.release();'現在'容器'將在異常返回時自動釋放。 –

+0

「在C++中有更好的方法嗎?」使用std :: string,而不是char數組。 –

+1

@NeilButterworth在這個設置中,'container'是一個要傳遞給C API的C風格的數據結構。練習的重點是在C++類和C POD之間進行轉換。 –

回答

2

我負責的數據結構

如何防止內存泄露

的解決方案是讓別人負責:)這聽起來卑鄙的記憶,但我覺得它見地。

將內存管理代碼放入一個RAII容器內,其單一責任是在超出範圍時釋放內存。由於C++ 11,即RAII容器可以無需開銷地實現,並且已經在標準庫中爲您執行:std::unique_ptr

只要內存由該唯一指針保存,如果由於異常或其他原因該唯一指針超出範圍,內存將被釋放。底層的裸指針可以從唯一指針中釋放,並且一旦所有可能拋出的代碼成功執行就返回。


也有可能發生在C++中唯一應用

的RAII容器在C甚至更好這個問題++,你保持容器爲對象的整個生命週期,而不是釋放內存入狂野。


PS。

if (c->message != nullptr) { 
    delete[] c->message; 
} 

測試是完全多餘的,這可以在unique_ptr被簡化爲

delete[] c->message; 
+0

謝謝,這使我的代碼更清晰,更容易推理。 – FSMaxB

0

商店所有的指針。理想情況下,如果C++ 14或更高版本(可能需要17個具有make唯一性的數組),則使用make_unique創建。

分配所有內容並檢查後,.release的唯一指針。

相關問題