为什么匿名 unique_ptr 值会立即被破坏
Why does anonymous unique_ptr value get destructed instantly
如果对象 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
表示)被销毁的块时。
但我不明白其他 2 个流程(d'tor A 2
和 d'tor A 3
在创建过程中调用 - 请参见示例)。这是否意味着在这些情况下引用计数从一开始就为 0,或者它增加到 1 并在之后立即减少。
P.S
这个案例让我很感兴趣,虽然它与任何真实案例无关,但澄清了我偶然处理的一个概念。
发生这种情况是因为我转换了 java-脚本,它被设置为创建一个成员并在没有中间变量的情况下使用它(例如 a().b().c()
而不是 _a=a(); _b=_a.b(); _c=_b.c()
)并且我不小心使用了我的 C++ 代码中的这个符号。
您混淆了 std::unique_ptr
和它管理的对象的生命周期,以及您可以使用它的 get
方法获得的指针的生命周期。
A std::unique_ptr
是动态分配对象的唯一所有者,当它的析构函数被调用时,它会在它持有的指针上调用删除辅助函数(在 std::make_unique
的情况下,它只会调用 delete
或 delete[]
,以在这种情况下合适的为准)
在第一种情况下,变量 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
方法,即 returns 受管理指针的副本。问题是临时的 std::unique_ptr<A>
在行尾被销毁,而你的指针是悬空的,它已经被删除了。取消引用并以任何方式使用是未定义的行为,任何事情都可能发生。
第 3 种情况相同,临时 std::unique_ptr
,您得到它的指针,但临时已被删除,因此在它管理的对象上调用 delete,我们有一个悬空指针。
每当你有一个智能指针时,永远不要在临时变量上调用 get
,首先将临时变量存储在局部变量中,这样当你仍在使用它时它不会超出范围正在管理。
如果对象 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
表示)被销毁的块时。
但我不明白其他 2 个流程(d'tor A 2
和 d'tor A 3
在创建过程中调用 - 请参见示例)。这是否意味着在这些情况下引用计数从一开始就为 0,或者它增加到 1 并在之后立即减少。
P.S
这个案例让我很感兴趣,虽然它与任何真实案例无关,但澄清了我偶然处理的一个概念。
发生这种情况是因为我转换了 java-脚本,它被设置为创建一个成员并在没有中间变量的情况下使用它(例如 a().b().c()
而不是 _a=a(); _b=_a.b(); _c=_b.c()
)并且我不小心使用了我的 C++ 代码中的这个符号。
您混淆了 std::unique_ptr
和它管理的对象的生命周期,以及您可以使用它的 get
方法获得的指针的生命周期。
A std::unique_ptr
是动态分配对象的唯一所有者,当它的析构函数被调用时,它会在它持有的指针上调用删除辅助函数(在 std::make_unique
的情况下,它只会调用 delete
或 delete[]
,以在这种情况下合适的为准)
在第一种情况下,变量 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
方法,即 returns 受管理指针的副本。问题是临时的 std::unique_ptr<A>
在行尾被销毁,而你的指针是悬空的,它已经被删除了。取消引用并以任何方式使用是未定义的行为,任何事情都可能发生。
第 3 种情况相同,临时 std::unique_ptr
,您得到它的指针,但临时已被删除,因此在它管理的对象上调用 delete,我们有一个悬空指针。
每当你有一个智能指针时,永远不要在临时变量上调用 get
,首先将临时变量存储在局部变量中,这样当你仍在使用它时它不会超出范围正在管理。