初始化shared_ptr成员变量,new和make_shared有什么区别?

12

当初始化一个shared_ptr成员变量时:

// .h
class Customer
{
public:
  Customer();

private:
  std::shared_ptr<OtherClass> something_;
}

// .cpp
Customer():
  something_(new OtherClass())
{
}

对比。

Customer():
  something_(std::make_shared<OtherClass>())
{
}

make_shared版本可以使用吗?我似乎总是看到第一种版本,哪种更好?


4
Herb Sutter刚刚写了一篇GOTW关于这个问题。请参见this,并查看一个问题,Herb没有明确说明。 - R Samuel Klatchko
@RSamuelKlatchko - 在你的回答中提供的第一个链接的更新链接,请使用https://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/。 - Guy Avraham
2个回答

15
make_shared 的唯一不允许的情况是:
  1. 如果你正在获取由其他人分配的裸指针,并将其存储在 shared_ptr 中。这通常在与 C API 接口时发生。
  2. 如果要调用的构造函数不是公共(make_shared 仅能调用公共构造函数)。这可能发生在工厂函数中,您希望强制用户从工厂创建对象。

    但是,有办法绕过这个问题。而不是具有私有构造函数,请使用公共构造函数。但是使构造函数采取一种只能由对该类拥有私有访问权限的人构造的类型。这样,只有对该类拥有私有访问权限的人才能使用该对象类型调用 make_shared

所以,是的,你可以这样做。

关于友元问题,在标准中是否提到了特定的函数用作友元?我可以想象一些实现将这项工作委托给辅助函数... - Matthieu M.
@MatthieuM.:我也有同样的疑问,这就是为什么我说“可能能够”的原因。我已经在comp.std.c++上提出了问题,我们将看看他们对此有何看法。如果不行,我认为这可能会成为一个不错的缺陷报告。 - Nicol Bolas

5
在这种情况下,使用make_shared不仅是被允许的,而且更好的选择。如果您使用new,它会在某个地方为您的客户分配内存,然后在另一个地方为您的shared_ptr分配内存,存储强引用和弱引用(对于弱指针和共享指针)。如果您使用make_shared,则只有一个内存位置拥有所有内容,因此只需要一个new。

我不确定我是否真正清楚,这就是GotW#89的目的,请阅读它,里面解释得很清楚。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接