【问题标题】:What happened when a destructor called in the constructor?在构造函数中调用析构函数时发生了什么?
【发布时间】:2016-11-15 11:11:41
【问题描述】:

我把这段代码写成如下:

#include <iostream>

using namespace std;

class T
{
    public:
    T()
    {
        cout << "bb\n";
        this -> ~T();
        cout << "zz" << endl;
    }
    ~T()
    {
        cout << "hello\n";
    };
};



int main()
{
    T a;
    return 0;
}

已编辑

对不起,应该是T a; 而不是T a(),现在我得到了输出:

bb
hello
zz
hello

但我对结果感到困惑。为什么这个程序可以成功运行?

已编辑

我不认为我的问题是重复的。在我的代码中,构造函数在函数完成之前调用析构函数。但是,它在那个问题中明确调用了两次析构函数。

【问题讨论】:

  • 最麻烦的解析。如果你解决了这个问题,肯定是 UB。
  • T a(); -- 这不调用函数。同样,通常,您可以用 C++ 编写任何类型的废话,并且可以无错误地编译。所以我的建议是不要浪费太多时间试图找出无意义的代码。
  • 如果不出意外,当a 超出范围,并且为已经销毁的对象调用析构函数时,将导致未定义的行为
  • @fredrik 看到 Hrishikesh Goyal 回答的变体,其中对象稍后不会再次被销毁。问题仍然是在构造函数中调用析构函数是否是未定义的行为

标签: c++


【解决方案1】:

这是未定义的行为:您正在对尚未完全构造的对象调用析构函数。

【讨论】:

  • 它在哪里指定它是 UF?
  • @StoryTeller 解释该引用与从构造函数调用析构函数的问题的相关性?
  • @M.M 这是一个问题还是一个要求!?多次调用构造函数是 UB。情况无关紧要。上面的答案可能是错误的,没有原因,但不是事实本身。
  • 这里有两个单独的问题,(a) 在构造函数中调用析构函数,(b) 调用析构函数两次。根据标题,我认为 OP 想了解 (a) 。该答案声称 (a) 没有证据,并且您的报价仅与 (b) 有关。
  • @M.M 是的,你可以摆弄新的位置,并争辩说根据[basic.life/6 OPs 示例会很好。但是 OP 询问了一个具有自动存储功能的变量。在那种情况下,它 UB。
【解决方案2】:

当您在构造函数中调用析构函数并且不使用 delete 语句显式删除动态生成的内存时,它将像普通函数调用一样工作。作为参考,我对代码进行了适当的更改,以便析构函数正常运行。

#include <iostream>
using namespace std;

class T
{public:
    T()
    {
        cout << "bb\n";
        this -> ~T();
        cout << "zz" << endl;
    }
    ~T(){cout << "hello\n";};
};


int main()
{
    T* a= new T();
    return 0;
}

输出:

bb
hello
zz

【讨论】:

  • @bolov 你将不得不用标准引号来证明这一点
  • 我在 C++14 标准中找不到任何使这段代码成为 UB 的东西
  • 虽然这个答案的第一段需要一些修正,但它并不完全像一个正常的函数调用,因为你当然不能访问该类的任何非静态成员(甚至无法评估指针 a)在析构函数调用之后
  • @M.M 当我有空的时候我会看看标准。
猜你喜欢
  • 1970-01-01
  • 2012-05-10
  • 2021-04-01
  • 2011-05-20
  • 1970-01-01
  • 2011-04-16
  • 2018-07-23
  • 2014-04-22
相关资源
最近更新 更多