1


0

非オブジェクトリソースをRAII準拠にする

私のコードでは windows.h`の HANDLE`を使っています。 彼らはのように使用されています

HANDLE h;
if (!openHandleToSomething(arg1, arg2, &h)) {
    throw std::exception("openHandleToSomething error");
}
/* Use the handle in other functions which can throw as well */
if (!CloseHandle(h)) {
    throw std::exception("closeHandle error");
}

ご覧のとおり、取得と解放の最中に起こりうるすべての例外にこの `CloseHandle`を挿入する必要があります。 そのため、忘れてしまった(または知らなかった空想的なSEH例外がある)可能性があります。つまり、メモリリークがあります。

最近、そのような場合から頭痛を取り除き、この CloseHandle`を自動的に呼び出すべきであるRAIIについて読みました。 また、Cには `new`で割り当てられたリソースの問題を解決する std

auto_ptr`のようなものがあることも見ました。

しかし、私は new`を使用しないので、そして HANDLE`は単に void * 'になるように typedef`されているので、どうやって `std

auto_ptr`を使うべきなのか疑問に思います。 どういうわけか、それにそれにカスタム削除関数を与えることは可能であるべきです( if(!CloseHandle(h)){throw std :: exception(" closeHandle error ");})。 デストラクタは、そのインスタンスがスコープ外になるたびに呼び出されるため、クラスの作成は別の方法になります。 しかし、すべての簡単なことのためにクラスを用意するのはやり過ぎです。

どのように私はこれらの偶然のメモリリークを修正することができますか?

ライブラリーがなく、依存性が非常に小さい純粋なCのソリューションをお勧めします。ただし、それらが本当に小さくて、とにかくほとんどの環境で使用されている場合を除きます。

6 Answer


6


頭に浮かぶ1つのアイデアは boost::shared_ptrを使用することです。 doc / libs / 1_40_0 / libs / smart_ptr / sp_techniques.html#handle [カスタムデリミタ]。


3


あなたはあなた自身の単純なRAIIイディオムを実装することができます。

class auto_handle {public:auto_handle():handle_(){}〜auto_handle(){if(!CloseHandle(handle_)){//ここではスローしないで(1)、他の方法でエラーを管理してください。 ハンドル

(1)http://www.parashift.co.jp/c -faq-lite / exceptions.html#faq-17.3 [あなたはデストラクタから投げてはいけません]

auto_handle h; if(!openHandleToSomething(arg1、arg2、


2


1) `+ auto_ptr <> +`を使用しないでください。 真剣に。 あなたはそれらの頭痛が欲しくありません - b / cを滑り降りるのは非常に簡単です。

2)基礎となるハンドルを提供するアクセサーを提供する単純なオブジェクトで `+ HANDLE `をラップします。 ` HANDLE +`をAPI呼び出しに渡すためにこれが必要になります。 (暗黙的な変換よりもアクセサの方が望ましいと思います。)

3)実際に「+ HANDLE +」をラッピングすることはありませんので、驚くべき落とし穴があるかどうかはわかりません。 もしあれば、私はそれらを指摘することはできません。 私は何も期待しないでしょう - それは不透明な値です。 しかし、それでは、誰が驚くべきことを期待していますか? 結局のところ、彼らは驚きです。

4)(もちろん)適切なdtorを実装する。


1


`+ std

auto_ptr `はこの状況に適していません。 それはその用途がありますが、これはそれらの1つではありません。 Greg Dによって提起された点を(並べ替えて)修正するために、 ` auto_ptr +`の問題は_pointer_セマンティクスの不足ではなく、むしろ奇妙な_ownership_セマンティクス-割り当てたときに、ポインタの_copy_が、代わりにポインタの_transfer_(つまり、割り当て先がリソースの新しい唯一の所有者になり、割り当て元には何もありません)。

ただし、ハンドルをクラスでラップしたいのですが。 私はこれを何度もしました、そしてそれはかなりうまくいきます。 特に驚くべきことではありませんが、Windowsでは多くのことにハンドルが使用されていることもあり、そのうちのいくつかには簡単に奇妙なことがあるかもしれません。


1


あなたはそれを関数に渡すときにあなたにハンドルを与える単純なラッパーが欲しいだけです:

#include class HWrapper {HANDLE h;ブールは閉じました。

public:HWrapper(A1引数1、A2引数2):閉じている(false){if(!openHandleToSomething(arg1、arg2、 void close(){closed = true;} //閉じると例外がスローされる if(!CloseHandle(h)){throw std :: runtime_error( "closeHandle error"); }}

/ *
         *  これにより、HANDLEを取る関数に渡すことができます。
         *  functionThatUsesHandleButMayThrow();関数を参照してください。 * / operator HANDLE(){return h;プライベート:/ *
     *  あなたのユースケースではコピーする必要はありません。
     *  そのため、明示的にコピーを禁止します。 *
     *  HWrapperオブジェクトをハンドルを必要とする関数に渡すだけです。
     *  組み込みのキャスト演算子がそれを使用するハンドルに変換します。
     *  これらの機能の中で。 このオブジェクトは所有権を保持していますが
     *  終了時にオブジェクトを削除することに対する責任。 *
     *  これは既存のコードとの単純な後方互換性を可能にします。 * / HWrapper(HWrapper const

;

void functionThatUsesHandleButMayThrow(HANDLE h){}


int main(){

{HWrapper w(A1、A2);をお試しください。

functionThatUsesHandleButMayThrow(w); / *
         *  あなたが近くに例外を投げることを気にしないならば。
         *  それからjsutはそれを範囲外にさせます。 デストラクタ
         *  クリーンアップしようとします。 失敗した場合は
         *  例外。 *
         *  他の例外が伝播している場合、これは必須です。
         *  例外をスローするとアプリケーションは終了します。 * /} catch(std :: exception const

試してください{

Hラッパーw2(A1、A2)。

functionThatUsesHandleButMayThrow(w2); / *
         *  あなたが例外を無視して気にするなら
         *  手動でclose()を呼び出します。 例外がスローされます。 *
         *  しかし、例外が既にスローされている場合
         *  functionThatUsesHandleButMayThrow()それではそれを試して閉じます
         *  デストラクタで、別の例外をスローしないでください。 * / w2.close(); catch(std :: exception const


0


ハンドルh; if(!openHandleToSomething(arg1、arg2、

ここにあります :

auto d = [](decltype(h)* a){if(a):: CloseHandle(* a); ; std :: unique_ptr buf(