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

问题描述 投票:2回答:1

如果对象unique_ptr<A>匿名传递(或完全不传递变量),其行为如何。如何从c'tor内知道unique_ptr是否具有引用(正在将其设置为命名变量)。

基本上,该示例显示了直接从返回的值对象中调用方法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 ++代码中使用了这种表示法。

c++ smart-pointers unique-ptr
1个回答
4
投票

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

A std::unique_ptr是动态分配的对象的唯一所有者,当调用析构函数时,它将在其持有的指针上调用删除器帮助程序函数(在std::make_unique的情况下,它将仅调用deletedelete[](在这种情况下适当))

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

现在,第二和第三种情况是相同的,第二种情况只是引入了一个临时变量,但是它什么都没有改变。

std::unique_ptr

当这样调用时,您将创建一个临时A * x = std::make_unique<A>(2).get(); ,并在该临时上调用std::unique_ptr<A>方法,该方法将返回所管理指针的副本。问题是临时get在行尾被破坏了,并且您的指针悬空了,它已经被删除了。取消引用并以任何方式使用都是未定义的行为,任何事情都可能发生。

第三种情况是相同的,临时的std::unique_ptr<A>,您得到的是它的指针,但是临时的被删除了,因此在它正在管理的对象上调用delete,并且我们有一个变暗的指针。

[只要有智能指针,就永远不要在临时变量上调用std::unique_ptr,首先将临时变量存储在局部变量中,因此当您仍在使用它所管理的指针时,它不会超出范围。

© www.soinside.com 2019 - 2024. All rights reserved.