因此,当使用shared_ptr<Type>
时,您可以写:
shared_ptr<Type> var(new Type());
我想知道为什么他们不允许更简单和更好(imo):
shared_ptr<Type> var = new Type();
要实现此类功能,您需要使用.reset()
:
shared_ptr<Type> var;
var.reset(new Type());
我习惯于OpenCV Ptr类,它是一个智能指针,允许直接赋值,一切正常
答案 0 :(得分:28)
语法:
shared_ptr<Type> var = new Type();
是copy initialization。这是用于函数参数的初始化类型。
如果允许,你可能会意外地将一个普通指针传递给一个带有智能指针的函数。此外,如果在维护期间,有人将void foo(P*)
更改为void foo(std::shared_ptr<P>)
,那么编译就会很好,从而导致未定义的行为。
由于此操作基本上取得了普通指针的所有权,因此必须明确地执行此操作。这就是为什么采用普通指针的shared_ptr
构造函数为explicit
- 以避免意外的隐式转换。
更安全,更有效的替代方案是:
auto var = std::make_shared<Type>();
答案 1 :(得分:20)
允许将原始指针隐式转换为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;
}
现在,如果隐式转换有效,则内存bar
将被shared_ptr
末尾的foo()
析构函数删除。当我们在std::cout << *bar;
中访问它时,我们现在有未定义的行为,因为我们正在取消引用已删除的指针。
在您的情况下,您直接在呼叫站点创建指针,因此无关紧要,但从示例中可以看出它可能会导致问题。
答案 2 :(得分:16)
允许这个允许你直接用指针参数调用函数,这很容易出错,因为你不一定知道你在调用网站上创建了一个共享指针。
void f(std::shared_ptr<int> arg);
int a;
f(&a); // bug
即使你忽略了这一点,你也可以在呼叫站点创建隐形临时站点,创建shared_ptr
非常昂贵。
答案 3 :(得分:8)
为什么[不]
shared_ptr
允许直接分配[复制初始化]?
我想知道背后的理由是什么? (现已删除评论)
TL; DR,制作任何构造函数(或演员)explicit
是为了防止它参与隐式转换序列。
explicit
的要求更好地说明了shared_ptr<>
是函数的参数。
void func(std::shared_ptr<Type> arg)
{
//...
}
并称为;
Type a;
func(&a);
这将编译,并且编写并且是不希望的和错误的;它的行为不会像预期的那样。
将用户定义的(隐式)转换(转换运算符)添加到混合中会变得更加复杂。
struct Type {
};
struct Type2 {
operator Type*() const { return nullptr; }
};
然后以下函数(如果不是显式的)将编译,但提供了一个可怕的错误......
Type2 a;
func(a);
答案 4 :(得分: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!
}
这段代码无法编译,这是一件好事。因为如果确实如此,该程序将表现出未定义的行为。
这是因为我们要两次删除相同的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
}