パス

2011-01-20 3 views
1

が、私はそのパス

class Base 
{ 
//some implementation 
}; 

class Deriv: public Base 
{ 
//implementation 
} 

class Case1 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case1(A* a):a_(a) 
    { 

    } 
}; 
class Case2 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case2(std::auto_ptr<A> a):a_(a.release()) 
    { 

    } 
}; 

のような多型クラス構造を持っていると私は、上記のもの多型のオブジェクトのいずれかを所有している第三級CASE1/2を持っているとしましょう。今は、このオブジェクトの所有権を取得するcase1/2クラスのコンストラクタにBase/Derivオブジェクトへのポインタを渡す必要があります。このオブジェクトをスマートポインタとして渡すべきですか?それを明確に私はあなたがスマートポインタを渡す必要があり、あなたはそれがスマートな名前を付ける必要があり、このオブジェクトの世話をターキン、または生のポインタ(ケース1)

Case1 c(new Deriv); 
//compared to 
Case2 c(std::auto_ptr<Base>(new Deriv)); 

答えて

3

のような非常に簡単な構文を許可することを可能にしていますようにするauto_ptrはポインタ(例えば、それは一時的なことはできません):

std::auto_ptr<Base> p(new Deriv); 
Case2 c(p); // this constructor would need to take the `auto_ptr` by reference 
      // so that it can steal ownership. 

あなたの最初の例では、Case1 c(new Deriv);new Derivが実行されたときに例外が間にスローされた場合、オブジェクトが漏洩する可能性があり、Case1オブジェクトはの所有権を取得する場合それはそのコンストラクタにあります。

スマートポインタの名前を付けない2番目の例では、状況によってはオブジェクトがリークする可能性があります。特に、これはif you have more than one argument to a functionで発生する可能性があります。

+0

間にある正確なゼロコードを意味しますか?なぜ私は一時的にすることもできないのです。 – Puppy

+0

@DeadMG:どこに? 'Case1'コンストラクタが生ポインタの引数をスマートポインタに割り当てる前に例外をスローできるものを実行すると、そのオブジェクトはリークします。私は、この件に関するHerb SutterのGOTW記事へのリンクを追加しました。コンストラクタが引数を1つしか取らない場合でも問題はありませんが、Boostガイドラインを含む最も優れたコーディングスタイルでは、この理由ですべてのスマートポインタに名前を付けることを推奨します。 –

+0

@James:彼が 'Case1 c(new Deriv);を呼び出すと、最初のDerivが構築され、Case1がそれを所有します。途中に投げる可能性のあるコードはありません。編集:その抜け穴はC++ 98について話しています。私が知る限り、このような欠陥を修正するために主に存在していたC++ 03にまだ存在することを実証するために別の記事を見つける必要があります。 – Puppy

0

あなたのクラスが渡されたオブジェクトを完全に所有している場合は、該当するすべてのケースでauto_ptrを使用して明示的にすることをお勧めします。明示的にauto_ptrを構築するのが最善のケースです。これは、APIユーザーがあなたがそのオブジェクトを所有していることを知っていて、所有権ミックスアップの可能性を減らすためです。

クラスに変数の所有権がある場合は、通常、生ポインタと破棄関数を提供する方法があります。

class best_practices { 
    std::function<void(A*)> destructor; 
    A* ptr; 
public: 
    best_practices(A* a, std::function<void(A*)> destructfunc) 
     : ptr(a), destructor(destructfunc) {} 
    ~best_practices() { 
     destructor(ptr); 
    } 
}; 
+0

あなたのサンプルコードは、私が私の答えで記述した問題を例示しています。 'std :: function 'のコピーコンストラクタは例外をスローする可能性があります(動的アロケーションが失敗するなど)。それがスローされた場合は、コンストラクタに渡された 'A'オブジェクトをリークしました。 –

+0

(接線に関連する唯一のノートでは、あなたのサンプルクラスにコピーコンストラクタとコピー代入演算子がありません) –

+0

動的割り当てに失敗した場合、漏れたオブジェクトよりも大きな問題があります。 – Puppy

0

私はこれがベストプラクティスであることのソースを持っていないが、あなたはいくつかの方法でリソースを格納するつもりなら、一般的に、私はそれが同じようにそのリソースを取得するのが最善です見つけます。

struct store_string 
{ 
    store_string(std::string s) : // potentially free, copy if not 
    s(std::move(s)) // free 
    {} 

    std::string s; 
}; 

やC +に:

この理由は、C++ 0xの中で、コピー/移動は引数が与えられたときに行われ、その後、あなただけのような、ストレージに移動ということです03、あなたのタイプが安く構築デフォルトにすることができた場合:

あなたのためにそう
struct store_string 
{ 
    store_string(std::string ss) // make necessary copy 
    { 
     s.swap(ss); // free 
    } 

    std::string s; 
}; 

、私はどうなる:

class Case2 
{ 
    boost::scoped_ptr<A> a_ //polymorphic data member owned by C 
public: 
    Case2(boost::scoped_ptr<A>& aa) 
    { 
     a.swap(aa); // take resource 
    } 
}; 

これは目を作りますあなたにとって単純なものであり、クライアントにリソースの管理方法を正確に知らせることができます。