15

Stuff を作成して Foo に所有権を与えることに関して、次の方法は合理的かつ効率的ですか?

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);
4

3 に答える 3

27

あなたは効率性に関心があるので、私は 2 つの点を指摘したいと思います。

shared_ptr<> は、移動構築がコピー構築より安価な多くの標準ライブラリ型の 1 つです。コピーでは参照カウンターをアトミックにインクリメントする必要があるのに対し、shared_ptr を移動するには参照データやカウンターに触れる必要がないため、shared_ptr を作成するコピーは遅くなります。Dave Abrahamsの記事「Want Speed? Pass by value!」から、特定の状況では、関数のパラメーターを値で受け取ることが実際に有益であることを知ることができます。これは次のケースの 1 つです。

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

  ...

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

今、あなたは書くことができます

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

ここで、引数は一時的なものであり、shared_ptr がコピーされることはありません (1 回か 2 回移動されただけです)。

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

于 2012-08-17T08:50:04.650 に答える
5

はい、それは完全に合理的です。このようにすると、共有ポインターの管理に必要な作業は、値渡しの場合は 2 回ではなく、1 回で済みます。コピーの作成を避けるために、make_shared の使用を検討することもできます。

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

できる唯一の改善点は、Foo が唯一の所有者になる場合 (つまり、Foo を作成した後に foosStuff を保持しない場合)、std::unique_ptr または boost::scoped_ptr (これはC++11 より前の同等のもの)、オーバーヘッドが少なくなります。

于 2012-08-17T08:40:34.457 に答える
3

make_fooヘルパーがある方が効率的かもしれません:

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

今、あなたは言うことができますauto f = make_foo();。または、少なくともmake_shared自分で呼び出しを使用してください。結果は、式shared_ptrから構築されたものよりも効率的である可能性があるためです。実際にコンストラクターの引数を取る場合は、プライベートな補助コンストラクターが適している可能性がありますnewStuff

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
    {  }
};

Foo::make上記のにラップするかmake_foo、直接使用できます。

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

そうは言っても、実際に所有権を共有しstd::unique_ptr<Stuff>ている場合を除き、より好ましいアプローチのように思えます。概念的にははるかに単純であり、いくらか効率的でもあります。その場合m_myStuff(new Stuff(std::forward<Args>(args)...))、 とマークされた行で言うでしょう#1

于 2012-08-17T08:47:34.720 に答える