为什么匿名unique_ptr值会立即被破坏

Why does anonymous unique_ptr value get destructed instantly

本文关键字:unique ptr 为什么      更新时间:2023-10-16

如果对象unique_ptr<A>是匿名传递的(或者根本不传递给变量(,它的行为如何。如何才能知道unique_ptr是否有来自c'tor的引用(它被设置到命名变量中(。

基本上,该示例显示直接从返回值对象调用方法get((方法。

class A
{
public:
A(int a):_a(a) {}
~A() { std::cout << "d'tor A " << _a << std::endl; }
int _a;
};

std::unique_ptr<A> f1()
{
auto p1 = std::make_unique<A>(1);
return p1;
}
A *f2()
{
A * x = std::make_unique<A>(2).get(); // d'tor called 2
std::cout << x->_a << std::endl; // this will print 2 although destructed.
return x;
}
A *f3()
{
return std::make_unique<A>(3).get(); // d'tor called 3
}

int main(int argc, const char * argv[]) {
auto a=f1();
auto b=f2();
auto c=f3();
return 0;
} // d'tor called 1

在上面的代码中,我理解d'tor A 1调用的定时,因为当退出唯一引用器(由局部变量a表示(被破坏的块时。

但我不理解其他两个流(在创建行调用的d'tor A 2d'tor A 3,请参见示例(。这是否意味着在这些情况下,引用计数从第一位开始为0,或者它上升到1,然后立即减少。

p.S

这个案件引起了我的兴趣,虽然它与任何真实的案件都无关,但它澄清了我偶然处理的一个概念。

之所以会发生这种情况,是因为我转换了java脚本,在该脚本中,它被用来创建一个成员,并在没有中间变量的情况下使用它(例如a().b().c()而不是_a=a(); _b=_a.b(); _c=_b.c()(,而我在c++代码中意外地使用了这种表示法。

您混淆了std::unique_ptr及其管理的对象的生存期,以及使用它的get方法可以获得的指针的生存期。

std::unique_ptr是动态分配对象的唯一所有者,当它的析构函数被调用时,它将在它所持有的指针上调用deleter辅助函数(在std::make_unique的情况下,它将只调用deletedelete[],在这种情况下以合适的为准(

在第一种情况下,变量a的类型是std::unique_ptr<A>std::unique_ptr位于堆栈上(由于复制省略,您不必调用std::move(,当main函数完成时,它将从堆栈中删除,调用析构函数,并删除对象,这是我们在使用std::unique_ptr时通常想要的行为。

第二种和第三种情况是一样的,第二种情况只是引入了一个临时变量,但它不会改变任何东西。

A * x = std::make_unique<A>(2).get();

当这样调用时,您将创建一个临时std::unique_ptr<A>,并在此临时上调用get方法,该方法返回托管指针的副本。问题是临时std::unique_ptr<A>在行的末尾被销毁,并且您的指针正在悬挂,它已经被删除。取消引用它并在中使用它是未定义的行为,任何事情都可能发生。

第三种情况是一样的,临时std::unique_ptr,你得到了它的指针,但临时被删除了,所以在它管理的对象上调用delete,我们有一个危险的指针。

无论何时有智能指针,都不要对临时指针调用get,首先将临时指针存储在本地变量中,这样当您仍在使用它所管理的指针时,它就不会超出范围。