C++ 为什么';t共享ptr允许直接分配

C++ 为什么';t共享ptr允许直接分配,c++,c++11,shared-ptr,smart-pointers,C++,C++11,Shared Ptr,Smart Pointers,因此,当使用shared\u ptr时,您可以编写: shared_ptr<Type> var(new Type()); 我习惯了OpenCV Ptr类,它是一个智能指针,允许直接赋值,一切正常 为什么[不]shared_ptr允许直接分配[复制初始化] 由于它是显式的,请参见和 我想知道这背后的理由是什么?(摘自现已删除的评论) TL;DR,使任何构造函数(或cast)显式是为了防止它参与隐式转换序列 explicit的要求最好用shared\u ptr作为函数的参数来说明 vo

因此,当使用
shared\u ptr
时,您可以编写:

shared_ptr<Type> var(new Type());
我习惯了OpenCV Ptr类,它是一个智能指针,允许直接赋值,一切正常

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

由于它是显式的,请参见和

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

TL;DR,使任何构造函数(或cast)
显式
是为了防止它参与隐式转换序列

explicit
的要求最好用
shared\u ptr
作为函数的参数来说明

void func(std::shared_ptr<Type> arg)
{
  //...
}
这将编译,并作为书面和不希望的和错误的;它不会像预期的那样运行

将用户定义(隐式)转换(强制转换运算符)添加到混合中会使问题变得更加复杂

struct Type {
};

struct Type2 {
  operator Type*() const { return nullptr; }
};
然后将编译以下函数(如果不是显式的),但提供了一个可怕的错误

Type2 a;
func(a);

允许这样做可以让您直接调用带有指针参数的函数,这很容易出错,因为您在调用站点不一定知道您正在使用它创建共享指针

void f(std::shared_ptr<int> arg);
int a;
f(&a); // bug
void f(标准::共享参数);
INTA;
f(a);//缺陷
即使您忽略了这一点,您也会在呼叫站点创建不可见的临时文件,并且创建
共享\u ptr
非常昂贵。

语法:

shared_ptr<Type> var = new Type();

允许将原始指针隐式转换为
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;
}
void foo(std::sharedptrbar){/*做点什么,不管做什么*/}
int main()
{
整型*条形=新整型(10);
富(巴);;
标准::cout
我想知道为什么他们不允许一个更简单更好的

随着您的经验越来越丰富,遇到的代码也越来越糟糕,您的观点也会改变

shared_ptr
,与所有标准库对象一样,其编写方式使其尽可能难以导致未定义的行为(即难以找到浪费每个人时间并破坏我们生存意志的bug)

考虑:

#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!
}
#包括
结构Foo{};
void do__something(std::shared_ptr pfoo)
{
//…有些事情
}
int main()
{
自动p=std::使_共享(/*args*/);
做某事(p.get());
p、 重置();//轰!
}
这段代码无法编译,这是一件好事。因为如果它编译了,程序将显示未定义的行为

这是因为我们将删除同一个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
}
#包括
结构Foo{};
void do__something(std::shared_ptr pfoo)
{
//…有些事情
}
int main()
{
自动p=std::使_共享(/*args*/);
做某事(p);
p、 reset();//确定
}

因为
std::shared\u ptr
的构造函数获取指针是
显式的
,并且没有
操作符获取指针。这不是一个赋值。除非你不使用
new
创建它,否则你将
删除
内存,而你没有
new
ed.@giò制作一个
shared_ptr
比大多数人希望的隐式转换要昂贵得多。对于其他类,它也可能是一个不明显的转换。例如,传递
5
并将其转换为
std::vector
将非常不直观。@giò这确实是一个大问题。@giò共享指针假定它拥有它是指针(并且只与其他共享指针共享)。如果您将原始指针传递给共享指针,则很可能另一段代码假定它拥有原始指针,并试图在某个点删除它。但是共享指针也会这样做!所以,是的,双重删除根本不好。
auto var = std::make_shared<Type>();
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;
}
#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!
}
#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
}