[英]When will the destructor be called?
#include <memory>
#include <iostream>
class Token { public:
Token() { std::cout << "Token()"; }
~Token() { std::cout << "~Token()"; }
};
template <class T>
std::unique_ptr<T> foo(T t0) {
return std::unique_ptr<T>(new T(t0)); };
int main() {
Token&& t = Token();
auto ptr = foo<Token>(t);
return 0;
}
On which occasions will the destructor be called?在什么情况下会调用析构函数?
I think it will be called firstly when we call Token()
, it creates a temporary object which is destructed immediately, then in the foo()
function when t0
is destructed, and then when main()
ends, and ptr
goes out of scope.我认为当我们调用
Token()
时它会首先被调用,它创建一个立即被破坏的临时对象,然后在foo()
函数中当t0
被破坏时,然后当main()
结束时,并且ptr
超出范围.
But my friend says otherwise, so how will it actually be?但是我的朋友说不是这样,那么实际情况如何呢?
When a scope ends and the automatic objects of that scope are destroyed, their destructors will be called in the reverse order the objects were created:当作用域结束并且该作用域的自动对象被销毁时,它们的析构函数将按照对象创建的相反顺序被调用:
int main() {
Token&& t = Token(); // Token1 constructed
// lifetime of Token1 extended because it was bound to t
auto ptr = foo<Token>(t); // creates a copy of Token1 for the argument of foo: Token2
// Token3 constructed by foo in dynamic memory
// and bound to ptr, which
// resides in automatic memory
// Token2 (temporary copy) is automatically destroyed
return 0;
// Last automatic object is destroyed: ptr
// thus, uniqe_ptr destroys Token3
// t is destroyed. This destroys Token1 because
// its lifetime-extending reference
// went out of scope
}
If you modify your Token class slightly you can observe this live:如果您稍微修改 Token 类,您可以实时观察:
class Token {
inline static int C = 1;
int c = C++;
public:
Token(Token const&) : Token() {}
Token(Token&&) : Token() {}
Token() { std::cout << "Token(" << c << ")\n"; }
~Token() { std::cout << "~Token(" << c << ")\n"; }
};
Output:输出:
Token(1)
Token(2)
Token(3)
~Token(2)
~Token(3)
~Token(1)
@bitmask's explanation about life-time is pretty clear. @bitmask 关于生命周期的解释非常清楚。 Besides, if you want to get the best performance, maybe you could implement the move constructor for your
class Token
, and then:此外,如果您想获得最佳性能,也许您可以为
class Token
实现移动构造函数,然后:
template <class T>
std::unique_ptr<T> foo(T& t0) { // pass-by-reference
return std::make_unique<T>(std::move(t0));
};
As you have used rvalue reference Token&& t
to extend the temporary Token
object's lifetime in function int main()
and the rvalue reference t
is a lvalue, so auto foo(T &)
will deduce T
as class Token
and accept t
as its parameter t0
according to Overload resolution .由于您在函数
int main()
中使用右值引用Token&& t
来延长临时Token
对象的生命周期,并且右值引用t
是左值,因此auto foo(T &)
会将T
推导为class Token
并接受t
作为其参数t0
根据 过载决议。 Furthermore, std::move
cast lvalue t0
to rvalue reference and std::make_unique
call the constructor which satisfies std::is_nothrow_constructable_v<Token,Token&&>
is true
, the move constructor and copy constructor are both candicate functions.此外,
std::move
cast lvalue t0
to rvalue reference 和std::make_unique
调用满足std::is_nothrow_constructable_v<Token,Token&&>
为true
的构造函数,移动构造函数和复制构造函数都是候选函数。 If you have implemented Token(Token&&)
, move constructor will be called.如果你已经实现了
Token(Token&&)
,移动构造函数将被调用。 Otherwise is copy constructor.否则是复制构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.