代码之家  ›  专栏  ›  技术社区  ›  Baz

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

  •  18
  • Baz  · 技术社区  · 13 年前

    关于创建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 回复  |  直到 13 年前
        1
  •  28
  •   sellibitze    13 年前

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

    shared_ptr<>是移动构造比复制构造便宜的许多标准库类型之一。复制构造shared_ptr的速度较慢,因为复制需要引用计数器原子递增,而移动shared_ptr根本不需要接触引用的数据或计数器。来自文章“ Want Speed? Pass by value! “通过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构造函数也必须动态分配引用计数器和deleter。make_shared只需一个分配就可以为您完成所有任务。

        2
  •  5
  •   jleahy    13 年前

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

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

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

        3
  •  3
  •   Kerrek SB    13 年前

    拥有一个 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 到上面 制作_foo ,或直接使用:

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

    也就是说,除非你真的 分享 所有权,a std::unique_ptr<Stuff> 听起来更可取的方法是:它在概念上更简单,也更有效。在这种情况下,你会说 m_myStuff(new Stuff(std::forward<Args>(args)...)) 在标记的行中 #1