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

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

shared_ptr<> 是移动构造比复制构造便宜的许多标准库类型之一。复制构造 shared_ptr 比较慢,因为复制需要引用计数器自动递增,而移动 shared_ptr 根本不需要接触引用的数据或计数器。从 Dave Abrahams 的文章“想要速度?按值传递! ”中可以了解到,在某些情况下,按值获取函数参数实际上是有益的。这是以下情况之一:

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 只需一次分配即可为您完成所有工作。

于 2012-08-17T08:50:04.650 回答
5

是的,这完全合理。这样,管理共享指针所涉及的工作只需要完成一次,如果您通过值传递它,则不需要两次。您还可以考虑使用 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可能比从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

于 2012-08-17T08:47:34.720 回答