简体   繁体   English

在C ++中显式调用构造函数和析构函数

[英]Explicitly calling constructors and destructors in C++

I know that one should not call destructors explicitly for local members as it results in undefined behaviour. 我知道不应该为本地成员显式调用析构函数,因为它会导致未定义的行为。 But still I want to understand the output for following piece of code : 但我还是想了解下面一段代码的输出:

#include <iostream>
using namespace std;

class Test
{
public:
    Test() { cout << "Constructor is executed\n"; }
    ~Test() { cout << "Destructor is executed\n"; }
    friend void fun(Test t);
};
void fun(Test t)
{
    Test(); //3.calls constructor and destructor
    t.~Test(); //4. calls destructor
}
int main()
{
    Test(); // 1. calls constructor and destructor
    Test t; // 2.calls constructor
    fun(t); 
    return 0; //5. compiler calls destructor for t
}

Expected output (3 destructor calls at the end): 预期输出(最后3个析构函数调用):

Constructor is executed
Destructor is executed
Constructor is executed
Constructor is executed
Destructor is executed
Destructor is executed
Destructor is executed

Actual output (4 destructor calls at the end): 实际输出(最后4个析构函数调用):

Constructor is executed
Destructor is executed
Constructor is executed
Constructor is executed
Destructor is executed
Destructor is executed
Destructor is executed
Destructor is executed

Where is th extra destructor call coming at the end? 到底哪个额外的析构函数调用?

You pass t to fun by value. 您传递tfun的价值。 It creates a copy. 它创建了一个副本。 The reason you don't see that is because you didn't make the copy constructor print anything. 你没有看到的原因是你没有让复制构造函数打印任何东西。 But you do see it destructed. 但你确实看到它被破坏了。

变量t通过值传递给函数fun - 因此在函数入口处构造了一个额外的副本(您没有看到这个打印,因为您的print语句仅用于默认构造函数),并且在退出时也被破坏(这是在t上,您还调用析构函数明确,所以它被破坏的两倍)。

You should at least print address of this in ctor and dtor message. 您至少应该在ctor和dtor消息中打印此地址。 I did it and got: 我做到了,得到了:

Constructor is executed 0020FC9F
Destructor is executed0020FC9F
Constructor is executed 0020FD77
Constructor is executed 0020FBAB
Destructor is executed0020FBAB
Destructor is executed0020FC84
Destructor is executed0020FC84
Destructor is executed0020FD77

This shows that you get an extra object at 20FC84 on which you call destructor twice without seeing it in default constructor. 这表明您在20FC84处获得了一个额外的对象,您可以在该对象上调用析构函数两次,而不会在默认构造函数中看到它。 It is because it has been created with an implicit (compiler provided) copy constructor to allow it to be passed by value to function fun . 这是因为它是使用隐式(编译器提供的)复制构造函数创建的,以允许它通过值传递给函数fun If you want to avoid that extra copy just declare fun to take its argument by ref: 如果你想避免这个额外的副本只是声明fun的参考ref:

void fun(Test& t)
{
    Test(); //3.calls constructor and destructor
    t.~Test(); //4. calls destructor
}

(do not forget the ref in the friend declaration...) (不要忘记朋友声明中的参考...)

It now gives as expected: 它现在按预期给出:

Constructor is executed 003EF90F
Destructor is executed003EF90F
Constructor is executed 003EF9E7
Constructor is executed 003EF827
Destructor is executed003EF827
Destructor is executed003EF9E7
Destructor is executed003EF9E7

In this statement in main 在主要的这个声明中

Test(); 

the constructor and the destructor of the temporary object is called. 调用临时对象的构造函数和析构函数。

So you have 所以你有了

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed
Constructor is executed
Destructor is executed
Destructor is executed
Destructor is executed
Destructor is executed

Then in the next statement in main 然后在主要的下一个声明中

Test t;

the constructor is called and you have 你会调用构造函数

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed Test t in main
Constructor is executed
Destructor is executed
Destructor is executed
Destructor is executed
Destructor is executed

Then in this statement in fun 然后在这个声明中充满乐趣

Test(); 

the constructor and the destructor of the temporary object are called and you have 你可以调用临时对象的构造函数和析构函数

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed Test t in main
Constructor is executed Test() in fun
Destructor is executed  Test() in fun
Destructor is executed
Destructor is executed
Destructor is executed

Then the destructor is called explicitly in fun 然后显式地调用析构函数

t.~Test(); 

and you have 你有

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed Test t in main
Constructor is executed Test() in fun
Destructor is executed  Test() in fun
Destructor is executed  t.~Test() in fun
Destructor is executed
Destructor is executed

In turn the compiler implicitly calls the destructor for its parameter t after exiting the function 反过来,编译器在退出函数后隐式调用析构函数的参数t

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed Test t in main
Constructor is executed Test() in fun
Destructor is executed  Test() in fun
Destructor is executed  t.~Test() in fun
Destructor is executed  The compiler calls the destructor for parameter t
Destructor is executed

And at last the local object t declared in main is also destroyed after exiting main 最后,在main中声明的本地对象t也在退出main之后被销毁

Constructor is executed Test() in main
Destructor is executed  Test() in main
Constructor is executed Test t in main
Constructor is executed Test() in fun
Destructor is executed  Test() in fun
Destructor is executed  t.~Test() in fun
Destructor is executed  The compiler calls the destructor for parameter t
Destructor is executed  The compiler calls the destructor for local object t declared in main

最后一个析构函数用于fun(),它占用了堆栈空间析构函数在所有当前线程完成执行后执行,它删除了函数分配的空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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