2012-08-17 20 views
5

Stuffを作成してFooの所有権を与えることに関して、以下のような合理的かつ効率的なアプローチがありますか?std :: shared_ptrをコンストラクターに渡す

class Foo 
{ 
    explicit Foo(const std::shared_ptr<Stuff>& myStuff) 
     : m_myStuff(myStuff) 
    { 
    } 

    ... 

private: 
    const std::shared_ptr<Stuff> m_myStuff; 
} 

std::shared_ptr<Stuff> foosStuff(new Stuff()); 
Foo f(foosStuff); 
+0

@sellibitze typo – Baz

+6

実際、「Foo」は所有権を取っていません。 'shared_ptr'のポイントは* share * ownershipです。 – juanchopanza

+0

また、 'std :: shared_ptr foosStuff(new Stuff());' – stefaanv

答えて

16

あなたが効率が興味を持っているので、私は2つの点を作りたいのですが:

のshared_ptr <>を移動工事がコピー建設よりも安価で、多くの標準ライブラリの種類の一つです。 shared_ptrを構築するコピーは、コピーすると参照カウンターを原子単位でインクリメントする必要がありますが、shared_ptrを移動すると参照されたデータやカウンターにはまったく触れる必要はありません。 Dave Abrahamsの記事「Want Speed? Pass by value!」から、特定の状況では、値によって関数パラメータを取ることが実際に有益であることがわかります。これは、これらのケースのいずれかです。

class Foo 
{ 
    explicit Foo(std::shared_ptr<Stuff> myStuff) 
    : m_myStuff(move(myStuff)) 
    {} 

    ... 

private: 
    std::shared_ptr<Stuff> m_myStuff; 
}; 

今、あなたは引数が一時的となしのshared_ptrが今までに(ただ一度か二度移動)コピーされ

Foo f (std::make_shared<Stuff>()); 

を書くことができます。

ここでstd :: make_sharedを使用すると、割り当てが1つしか行われないという利点があります。あなたの場合、自分でStuffオブジェクトを割り当てたので、shared_ptrコンストラクタは参照カウンタとdeleterを動的に割り当てる必要がありました。 make_sharedは1回の割り当てですべてを行います。

+1

私はそれが好きですmake_shared関数 – Baz

+1

btw:std :: unique_ptrに変更すると実際に値で渡します;) – sellibitze

+0

@sellibitzeクラスのshared_ptrをそのコンストラクタに渡すとどのような利点がありますかもしあなたがそれを保つつもりなら、確かにこの場合、unique_ptrを渡して、そのクラスからshared_ptrを構築する方が良いでしょうか? – jleahy

4

はい、これは完全に合理的です。このように、共有ポインタの管理に関係する作業は、値渡しの場合は2回ではなく、1回だけ行う必要があります。 make_sharedを使用してコピーの作成を避けることも考えられます。

std::shared_ptr<Stuff> foosStuff(std::make_shared<Stuff>()); 

fooが唯一の所有者であるのであればあなたが作ることができる唯一の改善は、あなたはSTDを使用するように切り替えることができ(すなわち。あなたはFooの作成後に周りfoosStuffを維持するつもりはない)されて:: unique_ptrをかboost :: scoped_ptr(これはC++ 11以前のバージョン)、オーバーヘッドが少なくなります。

Foo make_foo() { return Foo(std::make_shared<Stuff>()); } 

は今、あなたは auto f = make_foo();を言うことができます。

+0

私はshared_ptrにしか慣れていないので、他のスマートポインタについてもっと学びましょう。 – Baz

+0

'scoped_ptr'とは何ですか、それはC++の一部ではありませんか?多分あなたは 'std :: unique_ptr'を意味するでしょうか?そしてなぜカスタムディレクター? –

+0

@ChristianRau:私はそれが 'boost :: scope_ptr'を意味すると思います。デリタービットは、以前の(ステルス)編集の時代遅れの参照かもしれませんか? –

3

make_fooヘルパーを持っている方が効率的かもしれません。または、少なくともmake_shared呼び出しを自分で使用してください。その結果、shared_ptrnew式から構築されたものより効率的になる可能性があります。 Stuffが実際にコンストラクタ引数を取る場合と、民間補助コンストラクタは、適切な次のようになります。あなたは上記のmake_fooFoo::makeをラップ、またはそれを直接使用することができますいずれか

struct Foo 
{ 
    template <typename ...Args> 
    static Foo make(Args &&... args) 
    { 
     return Foo(direct_construct(), std::forward<Args>(args)...); 
    }; 

private: 

    struct direct_construct{}; 

    template <typeaname ...Args> 
    Foo(direct_construct, Args &&... args) 
    : m_myStuff(std::make_shared<Stuff>(std::forward<Args>(args)...)) // #1 
    { } 
}; 

auto f = Foo::make(true, 'x', Blue); 

、言ったあなたがない限り本当にの共有の所有権は、std::unique_ptr<Stuff>の方がより好ましいアプローチのように聞こえます。それは、概念的にははるかに単純であり、やや効率的です。その場合、#1と記された行にm_myStuff(new Stuff(std::forward<Args>(args)...))と書かれています。

+0

+1のための+1 unique_ptr: – sellibitze