使用new运算符定义std :: shared_ptr时出错

Fde*_*deF 4 c++ shared-ptr c++11

我试图通过以下方式定义一个std::shared_ptrwith new运算符:

#include <memory>

struct A {
};

int main() {

  std::shared_ptr<A> ptr = new A();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我获得了以下编译时错误:

main.cpp:在函数'int main()'中:

main.cpp:8:30:错误:从'A*'转换为非标量类型'std :: shared_ptr'请求std :: shared_ptr ptr = new A();

无论如何,以下肯定有效:

      std::shared_ptr<A> ptr{new A()};
Run Code Online (Sandbox Code Playgroud)

你们中有谁知道为什么会这样吗?

Lig*_*ica 6

tl; dr:这是相关构造函数的结果explicit.

初始化时=,您将调用复制初始化.C++不允许shared_ptr从原始指针复制初始化,因为从一些任意原始指针到shared_ptr实际上没有管理它的意外隐式转换最终会很容易.

这样,你可以将原始指针"捕获"到a中的唯一方法shared_ptr就是非常刻意且非常明确(正如你在第二个例子中所做的那样).现在,只有在这个初始化器中,您必须记住不要使用您已在其他地方管理的指针.

特定线路有什么危险std::shared_ptr<A> ptr = new A()吗?不,但你所看到的是各种C++规则协同工作的结果.


Hay*_*ayt 5

您可以将您的陈述想象成这样的 2 行。

A* a = new A();
std::shared_ptr<A> ptr = a;
Run Code Online (Sandbox Code Playgroud)

虽然在这种情况下,这在更复杂的代码中可能是正确的,但它可能会导致潜在的陷阱,因此不允许对原始指针进行复制初始化。

想象

A* a = new A();
//.....
std::shared_ptr<A> ptr = a;
//.....
std::shared_ptr<A> ptr2 = a; //second ptr holding a... UB
Run Code Online (Sandbox Code Playgroud)

在这里,您将有 2 个共享指针持有同一个对象,这会引起麻烦。

为了避免这些“隐式”错误,C++ 不允许这种初始化。

虽然您仍然可以使用构造函数进行相同的操作,但它更“冗长”并且更难意外分配指针。

std::shared_ptr<A> ptr{ new A() };
Run Code Online (Sandbox Code Playgroud)

这看起来更像是构造一个新对象,并且可能不会意外导致错误分配。

在现代中创建共享指针的首选方法是

auto ptr = std::make_shared<A>();
Run Code Online (Sandbox Code Playgroud)

  • 不,那不是任务。 (3认同)