2012-08-17 194 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 2012-08-17 08:41:49

+6

不是真的,'Foo'不*取*拥有权。 'shared_ptr'的要点是*共享*所有权。 – juanchopanza 2012-08-17 08:43:44

+0

或者更喜欢'std :: shared_ptr foosStuff(new Stuff());' – stefaanv 2012-08-17 08:47:37

回答

16

既然你有兴趣的效率,我想强调两点:

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

现在你可以写

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

,其中参数是一个临时的,没有的shared_ptr被抄过(刚搬到一次或两次)。

这里使用std :: make_shared具有只有一个分配完成的优点。在你的情况下,你自己分配了Stuff对象,并且shared_ptr构造函数也必须动态地分配引用计数器和删除器。 make_shared只用一个分配就可以完成所有的工作。

+1

我喜欢这个make_shared函数 – Baz 2012-08-17 08:54:04

+1

btw:如果你改变为std :: unique_ptr你实际上_HAVE_传递它的价值;) – sellibitze 2012-08-17 08:56:25

+0

@sellibitze将类shared_ptr传递给它的构造函数有什么好处如果你不打算保留它。当然在这种情况下,最好传入一个unique_ptr并让该类从其构造shared_ptr? – jleahy 2012-08-17 09:32:03

4

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

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

你可以做的唯一的改进是,如果美孚是成为唯一拥有者(即你不打算继续foosStuff创建美孚之后各地),那么你可以切换到使用一个std ::的unique_ptr或boost :: scoped_ptr(这是pre-C++ 11的等价物),这将有较少的开销。

+0

好吧,我应该研究更多关于其他智能指针的知识,因为我只是非常熟悉shared_ptr。 – Baz 2012-08-17 08:43:15

+0

什么是'scoped_ptr',它不是C++的一部分?也许你的意思是'std :: unique_ptr'?为什么自定义删除? – 2012-08-17 08:54:20

+0

@ChristianRau:我想这意味着'boost :: scope_ptr'。 deleter位可能是对较早(隐形)编辑的过时引用? – 2012-08-17 09:00:45

3

这可能是更有效的有make_foo帮手:

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

现在你可以说auto f = make_foo();。或者至少自己使用make_shared调用,因为生成的shared_ptr可能比由new表达式构造的效率更高。

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

这就是说,除非你:如果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,或直接使用它真的是分享所有权,std::unique_ptr<Stuff>听起来像更可取的方法:它在概念上更简单,也更有效。在这种情况下,您会在标记为#1的行中说m_myStuff(new Stuff(std::forward<Args>(args)...))

+0

+1为提及unique_ptr :) – sellibitze 2012-08-17 08:51:10

相关问题