为什么shared_ptr不允许直接赋值

giò*_*giò 15 c++ smart-pointers shared-ptr c++11

所以在使用时shared_ptr<Type>你可以写:

shared_ptr<Type> var(new Type());
Run Code Online (Sandbox Code Playgroud)

我想知道为什么他们不允许更简单和更好(imo):

shared_ptr<Type> var = new Type();
Run Code Online (Sandbox Code Playgroud)

而不是要实现这样的功能,您需要使用.reset():

shared_ptr<Type> var;
var.reset(new Type());
Run Code Online (Sandbox Code Playgroud)

我习惯于OpenCV Ptr类,它是一个智能指针,允许直接赋值,一切正常

Max*_*kin 28

语法:

shared_ptr<Type> var = new Type();
Run Code Online (Sandbox Code Playgroud)

复制初始化.这是用于函数参数的初始化类型.

如果允许,您可能会意外地将普通指针传递给采用智能指针的函数.此外,如果在维护期间,有人改变void foo(P*)void foo(std::shared_ptr<P>)将编译,就像细,导致不确定的行为.

由于此操作基本上取得了普通指针的所有权,因此必须明确地执行此操作.这就是为什么shared_ptr采用普通指针的构造函数explicit- 以避免意外的隐式转换.


更安全,更有效的替代方案是:

auto var = std::make_shared<Type>();
Run Code Online (Sandbox Code Playgroud)

  • @giò确实是个大问题. (4认同)

Nat*_*ica 20

允许将原始指针隐式转换为a的问题std::shared_ptr可以用

void foo(std::shared_ptr<int> bar) { /*do something, doesn't matter what*/ }

int main()
{
    int * bar = new int(10);
    foo(bar);
    std::cout << *bar;
}
Run Code Online (Sandbox Code Playgroud)

现在,如果隐式转换工作,那么内存bar点会被shared_ptr析构函数删除foo().当我们去访问它时,std::cout << *bar;我们现在有未定义的行为,因为我们正在取消引用已删除的指针.

在您的情况下,您直接在调用站点创建指针,因此无关紧要,但从示例中可以看出它可能会导致问题.


mil*_*bug 16

允许这允许您直接使用指针参数调用函数,这很容易出错,因为您在调用站点时不一定知道您正在从中创建共享指针.

void f(std::shared_ptr<int> arg);
int a;
f(&a); // bug
Run Code Online (Sandbox Code Playgroud)

即使您忽略了这一点,也可以在呼叫站点创建不可见的临时站点,并且创建shared_ptr非常昂贵.


Nia*_*all 8

为什么[不] shared_ptr允许直接分配[复制初始化]?

因为它是explicit,请看这里这里.

我想知道背后的理由是什么?(现已删除评论)

TL; DR,使任何构造函数(或explicit强制转换)都阻止它参与隐式转换序列.

对于要求explicit与被更好地示出shared_ptr<>为功能的参数.

void func(std::shared_ptr<Type> arg)
{
  //...
}
Run Code Online (Sandbox Code Playgroud)

并称为;

Type a;
func(&a);
Run Code Online (Sandbox Code Playgroud)

这将编译,并编写,是不希望和错误的; 它不会像预期的那样表现.

将用户定义的(隐式)转换(转换运算符)添加到组合中会变得更加复杂.

struct Type {
};

struct Type2 {
  operator Type*() const { return nullptr; }
};
Run Code Online (Sandbox Code Playgroud)

然后以下函数(如果不是显式的)将编译,但提供了一个可怕的错误...

Type2 a;
func(a);
Run Code Online (Sandbox Code Playgroud)


Ric*_*ges 8

我想知道为什么他们不允许更简单和更好......

随着您变得更有经验并遇到更糟糕的错误代码,您的意见也会发生变化.

shared_ptr<>,就像所有标准库对象一样,以尽可能使其难以导致未定义的行为(即很难找到浪费每个人的时间并破坏我们生活意愿的错误).

考虑:

#include<memory>

struct Foo {};

void do_something(std::shared_ptr<Foo> pfoo)
{
  // ... some things
}

int main()
{
  auto p = std::make_shared<Foo>(/* args */);
  do_something(p.get());
  p.reset();  // BOOM!
}
Run Code Online (Sandbox Code Playgroud)

这段代码无法编译,这是件好事.因为如果确实如此,该程序将表现出未定义的行为.

这是因为我们要删除两次相同的Foo.

该程序将编译,并且格式正确.

#include<memory>

struct Foo {};

void do_something(std::shared_ptr<Foo> pfoo)
{
  // ... some things
}

int main()
{
  auto p = std::make_shared<Foo>(/* args */);
  do_something(p);
  p.reset();  // OK
}
Run Code Online (Sandbox Code Playgroud)