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)
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
非常昂贵.
为什么[不]
shared_ptr
允许直接分配[复制初始化]?
我想知道背后的理由是什么?(现已删除评论)
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)
我想知道为什么他们不允许更简单和更好......
随着您变得更有经验并遇到更糟糕的错误代码,您的意见也会发生变化.
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)