【问题标题】:Member's destructor calling from default constructor从默认构造函数调用成员的析构函数
【发布时间】:2018-05-13 12:44:36
【问题描述】:
class Part
{
public:
    ~Part() = delete;
};

class CL
{
public:
    CL(){} //error: deleted destructor call
    ~CL();
    Part part;
};

int main()
{
}

此代码给出了与Part 的已删除析构函数调用相关的错误。成员析构函数调用的默认构造函数的上下文是什么?

P.S:据我所知,Part 成员的析构函数必须在 ~CL() 中调用,但它不是专门为演示而定义的,默认构造函数强制它在任何地方

【问题讨论】:

  • “成员析构函数调用的默认构造函数中的上下文是什么?c++ 构造函数析构函数删除操作符” Part part; 当然。而且它并不是真正的默认构造函数的上下文。
  • 为什么Part::~Part()被删除了?
  • 如果我评论“CL(){}”,代码编译得很好。显然,默认 ctor 中就是这种情况
  • "显然,默认 ctor 就是这种情况"不,不是,它是从 ~CL() 调用的
  • 这是否与构造函数必须销毁已初始化的成员以防异常有关?

标签: c++ constructor language-lawyer destructor


【解决方案1】:

每个构造函数都需要访问其成员的析构函数。当构造函数抛出异常时,它必须能够销毁在抛出异常之前初始化的每个成员。您可以验证这对于每个构造函数都是正确的。如果您尝试向构造函数添加任意参数,即使使用复制和移动构造函数,错误仍然会发生。

正如 cmets 中提到的,CL() = default; 不会产生错误。这是因为CL() = default; 只会导致编译器生成它通常会生成的隐式默认构造函数。在这种情况下,CL 似乎有一个deleted implicitly-declared default constructor,这意味着自动生成的隐式默认构造函数将被删除。如果您尝试以下操作,您会发现默认构造函数实际上不可用:

#include <type_traits>

class Part
{
public:
    ~Part() = delete;
};

class CL
{
public:
    CL() = default;
    ~CL();
    Part part;
};

// This assert passes
static_assert(std::is_default_constructible<CL>::value == false, "");

但是,我无法准确解释为什么 CL 有一个已删除的隐式声明的默认构造函数,我也无法解释为什么CL() noexcept {}; 不起作用。

【讨论】:

  • CL 有一个已删除的构造函数,因为 [special]/4: 有一个潜在构造的子对象,其析构函数不可访问/已删除
【解决方案2】:

首先,根据[special]p5PartCL可能构造的子对象

对于一个类,它的非静态数据成员,它的非虚拟直接基类,如果这个类不是抽象的,它的虚拟基类被称为它的可能构造的子对象

所以Part 的析构函数可能会根据[class.base.init]p12 调用,无论nonexcept 是否存在。

在非委托构造函数中,每个可能构造的类类型子对象的析构函数都可能被调用。

因此,根据[class.dtor]p12,程序格式不正确。

如果一个可能被调用的析构函数被删除或无法从调用的上下文中访问,则该程序是格式错误的。

请注意,即使实际上并未调用已删除的析构函数,只要析构函数可能被调用,程序就是非良构的。

【讨论】:

  • 关于最后一段,可能被调用是一个有点学术性的术语,因为调用这个特定的构造函数并没有实际的方式调用析构函数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 2011-01-16
  • 2012-12-24
  • 2013-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多