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

时间:2016-07-05 14:23:52

标签: c++ c++11

我知道不应该为本地成员显式调用析构函数,因为它会导致未定义的行为。但我还是想了解下面一段代码的输出:

#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
}

预期输出(最后3个析构函数调用):

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

实际输出(最后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

最后会有哪些额外的析构函数调用?

5 个答案:

答案 0 :(得分:5)

您按价值将t传递给fun。它创建了一个副本。 你没有看到的原因是因为你没有让复制构造函数打印任何东西。 但你确实看到它被破坏了。

答案 1 :(得分:2)

变量t按值传递给函数fun - 因此在输入函数时会构造一个额外的副本(您不会看到此打印,因为您的print语句是只有默认构造函数),并且在退出时也被销毁(这是t,你也可以在其上显式调用析构函数,因此它会被破坏两次)。

答案 2 :(得分:2)

您至少应该在ctor和dtor消息中打印此地址。我做到了,得到了:

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

这表明您在20FC84处获得了一个额外的对象,您可以在其中调用析构函数两次,而不会在默认构造函数中看到它。这是因为它是使用隐式(编译器提供的)复制构造函数创建的,以允许它通过值传递给函数fun。如果你想避免这个额外的副本,只需声明fun通过ref:

获取它的参数
void fun(Test& t)
{
    Test(); //3.calls constructor and destructor
    t.~Test(); //4. calls destructor
}

(不要忘记朋友声明中的参考...)

它现在按预期给出:

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

答案 3 :(得分:2)

在主要

中的这个陈述中
if(str != null && !str.isEmpty())

调用临时对象的构造函数和析构函数。

所以你有

Test(); 

然后在主

的下一个声明中
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

调用构造函数,你有

Test t;

然后在这个有趣的声明中

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

临时对象的构造函数和析构函数被调用,你有

Test(); 

然后在fun中显式调用析构函数

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

你有

t.~Test(); 

反过来,编译器在退出函数

后隐式调用析构函数的参数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
Destructor is executed

最后,在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

答案 4 :(得分:0)

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