将std :: shared_ptr传递给构造函数

时间:2012-08-17 08:36:57

标签: c++ std

以下是创建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);

3 个答案:

答案 0 :(得分:22)

既然你对效率感兴趣,我想提出两点:

的shared_ptr&LT;&GT;是移动构造比复制构造便宜的许多标准库类型之一。复制构造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;
};

现在你可以写

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

其中参数是临时的,并且没有复制shared_ptr(只移动一次或两次)。

这里使用std :: make_shared的优点是只进行了一次分配。在您的情况下,您自己分配了Stuff对象,而shared_ptr构造函数也必须动态分配引用计数器和删除器。只需一次分配,make_shared就能为您完成所有工作。

答案 1 :(得分:4)

是的,这是完全合理的。这样,管理共享指针所涉及的工作只需要完成一次,而不是两次,如果你按值传递它。您还可以考虑使用make_shared来避免复制构造。

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

你可以做的唯一改进是如果Foo是唯一的所有者(即你在创建Foo之后不会保留foosStuff)然后你可以切换到使用std :: unique_ptr或boost :: scoped_ptr (这是前C ++ 11的等价物),它的开销会更少。

答案 2 :(得分:3)

拥有make_foo帮助器可能更有效:

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

现在你可以说auto f = make_foo();。或者至少自己使用make_shared调用,因为生成的shared_ptr可能比从new表达式构造的Stuff更有效。如果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的行中说{{1}}。