2017-07-19 9 views
0

C++でC-APIを実装していて、C++のようなデータ構造をC-APIの既存のデータ構造に変換する必要があります。'new'を連続して使用したときの割り当て失敗時のメモリリークを防ぐ方法

私はデータ構造のメモリを担当していますので、私は新しいものと削除することができますが、私の理解から、次のC++ 11コードはメモリリークを起こすことがあります(これはちょっと落とした例です):

#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++でこれを行うには良い方法はありますか?

メモリはnewdeleteで管理されており、std::bad_allocをキャッチ同じtryブロックで二回newを使用することが起こるならば、この問題は、C++アプリケーションだけで発生する可能性があります。

スマートポインタなどの方法で解決できますか?

+0

'auto c = std :: make_unique (); ...; return c.release(); '異常終了時に' container'は自動的に解放されます。 –

+0

"これをC++で行うより良い方法はありますか?" charの配列ではなく、std :: stringを使用します。 –

+1

@NeilButterworthこの設定では、 'container'はC APIに渡されるCスタイルのデータ構造体です。この演習のポイントは、境界上のC++クラスとC PODの間の変換です。 –

答えて

2

私はメモリを防ぐためにどのようなデータ構造

のメモリを担当していますがソリューションは他の誰かが責任を作るために悪意に満ち聞こえるかもしれません:)ですが、私はそれを見つける

を漏らします洞察力のある

スコープ外でメモリを解放することを単一の責任とするRAIIコンテナ内にメモリ管理コードを挿入します。 RAIIコンテナであるC++ 11は、オーバーヘッドなしで実装できるため、標準ライブラリで既に実装されています。std::unique_ptr

メモリがその一意のポインタによって保持されている限り、一意のポインタが例外などの理由で範囲外になると、メモリは解放されます。根本的な裸のポインタは、一意のポインタから解放され、スローされる可能性のあるコードがすべて正常に実行された後に返されます。


この問題はまた、あなたが代わりにメモリを解放するオブジェクトの全体の寿命のための容器を保つところRAIIコンテナはC++にも優れている

C++アプリケーションだけで発生することができます野生。


PS。

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

テストが完全に冗長であり、これは単なる

delete[] c->message; 
+0

ありがとう、これは私のコードをはるかにクリーンで簡単に推論することができます。 – FSMaxB

0

Storeにunique_ptr内のすべてのポインタを簡素化することができます。 C++ 14以上が理想的であればmake_uniqueで作成します(make独自の配列の場合は17が必要な場合があります)。

すべてを割り当ててチェックした後、.releaseは一意のポインタです。

関連する問題