简体   繁体   English

什么时候调用析构函数?

[英]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
}

Demo演示

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)

( live demo ) 现场演示

@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM