3

我有一个类型的析构函数已被显式删除;我想让该类型的一个实例成为另一个类的成员。

我的期望是,如果没有尝试删除包含类的实例(即,包含类的析构函数将无效),那应该没问题。

但是,当尝试实例化父类的构造函数时,clang (v3.3) 和 g++ (v 4.6.3) 都会出错。

例如:

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

class MyClass
{
  public:
    MyClass() = default;
    ~MyClass() = delete;

  private:
    DeletedDtor a;
};

int main() {
    MyClass *p = new MyClass();
}

在 g++ 下,这给出:

test.cpp: In function ‘int main()’:
test.cpp:19:30: error: use of deleted function ‘MyClass::MyClass()’
test.cpp:11:5: error: ‘MyClass::MyClass()’ is implicitly deleted because the default definition would be ill-formed:
test.cpp:11:5: error: use of deleted function ‘DeletedDtor::~DeletedDtor()’
test.cpp:5:5: error: declared here

自己定义 MyClass 构造函数,而不是让它采用默认实现,也无济于事:

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

class MyClass
{
  public:
    MyClass();
    ~MyClass() = delete;

  private:
    DeletedDtor a;
};

MyClass::MyClass() : a() {}

int main() {
    MyClass *p = new MyClass();
}

这给出了编译错误:

test2.cpp: In constructor ‘MyClass::MyClass()’:
test2.cpp:18:24: error: use of deleted function ‘DeletedDtor::~DeletedDtor()’
test2.cpp:5:5: error: declared here
4

4 回答 4

6

这种行为的一些基本原理:有一种情况,成员对象的析构函数在包含对象的析构函数之外自动调用:以防包含对象的构造函数抛出(某些东西)。在构造函数退出之前,已经构造的成员和基类子对象的析构函数以构造相反的顺序被调用。

于 2013-07-22T12:13:19.420 回答
4

您的问题不正确,构造函数被定义为已删除,因为此类成员的析构函数被定义为已删除,但是,您只需编写

DeletedDtor* d = new DeletedDtor();

一切都会正常工作(当然没有删除),所以 gcc 和 clang 都是正确的。

n3376 12.1/8

类 X 的默认默认构造函数在以下情况下定义为已删除

— 任何直接或虚拟基类或非静态数据成员都具有带有析构函数的类型,该析构函数 已从默认的默认构造函数中删除或不可访问。

于 2013-07-22T11:17:39.520 回答
2

我没有实际 C++ 标准的副本,但最新的工作草案说:

8.4.3/2[dcl.fct.def.delete]

隐式或显式引用已删除函数(而不是声明它)的程序是格式错误的。[...]

当一个对象被销毁时,任何成员对象的析构函数都会被隐式调用,即使你没有销毁任何对象,一个默认的析构函数仍然会被创建,它引用了它的成员的析构函数。基于此,您得到的错误对我来说似乎是正确的。

于 2013-07-22T11:34:36.307 回答
0

您不能使用已删除的析构函数来保存该类的实例。但是你可以DeletedDtor在你的MyClass:

class MyClass
{
  public:
    MyClass() = default;

  private:
    DeletedDtor* a;
};
于 2013-07-22T11:10:39.103 回答