如果对象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 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
),并且当[ 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
,首先将临时变量存储在局部变量中,因此当您仍在使用它所管理的指针时,它不会超出范围。