“= default”析构函数和空析构函数有什么区别?

43

我希望防止用户将我的类用作自动变量,因此我编写了以下代码:

class A {
private:
  ~A() = default;
};

int main() {
  A a;
}

我原本以为这段代码无法编译,但是使用g++却没有出现错误。

然而,当我将代码改成以下形式时:

class A {
private:
  ~A(){}
};

int main() {
  A a;
}

现在,g++报错说~A()是私有的,这正是我所期望的。

"=default"析构函数和空析构函数有什么区别?


4
什么版本的gcc? - user3920237
1
阅读例如 此析构函数参考,不同之处在于用户提供的析构函数(即使它是空的)是 非平凡 的,而从参考中得知:“具有平凡析构函数的对象不需要 delete-expression,并且可以通过简单地释放其存储来处理。” - Some programmer dude
8
在你的情况下,gcc4.9和clang3.5都无法编译你的第一个例子,没有区别。这一定是你版本的gcc存在bug。 - Praetorian
4
我认为相关的错误报告是[54812](https://gcc.gnu.org/bugzilla/show_bug.cgi?id = 54812)。 - user3920237
@JoachimPileborg 当它说不需要delete-expression时,是指对象是否动态分配?而“释放它们的存储空间”是否意味着调用析构函数? - David G
显示剩余4条评论
1个回答

32

你的第一个例子不应该编译。这表示编译器在编译时出现了错误,这个问题在 gcc 4.9 及更高版本中已经被修复。

使用 = default 定义的析构函数在这种情况下是平凡的。可以通过 std::is_trivially_destructible<A>::value 进行检测。

更新

C++11(和 C++14)规定,如果有用户声明的析构函数(且如果您没有用户声明的移动特殊成员),则复制构造函数和复制赋值运算符的隐式生成仍然会发生,但该行为已被弃用。这意味着如果您依赖它,您的编译器可能会给您一个弃用警告(或者可能不会)。

两段内容均已翻译。

~A() = default;

而且:

~A() {};

都是由用户声明的,因此在这一点上它们没有区别。 如果您使用这些形式之一(而没有声明移动成员),则应明确默认、显式删除或显式提供复制成员,以避免依赖已弃用的行为。

如果声明移动成员(无论是否声明了析构函数),则复制成员会被隐式删除。


2
@delphifirst:编译器错误现在非常普遍。当我还是学生的时候,早在1980年代初,我们就知道任何不良行为都是我们代码中的错误,而不是编译器的错误。今天,我经常让编译器崩溃(ICE,内部编译器错误),那么这个问题的责任就毫无疑问地落在了谁的头上... - Cheers and hth. - Alf
@HowardHinnant:我想讨论一下默认声明和未声明的区别,因为这与标准中“用户声明”的用法有关,例如在C++11 §12.8/18中。可以吗? - Cheers and hth. - Alf
@Cheersandhth.-Alf:很高兴能帮忙,但我不理解你的问题。如果你问的是=defaulted特殊成员是否是用户声明的,答案是肯定的,但不是用户提供的。 - Howard Hinnant
1
@HowardHinnant:它直接回答了OP的问题:“= default”析构函数和空析构函数之间有什么区别?像我所提到的段落中提到的未来代码含义的差异,在我看来非常重要。这绝对是一个区别。 - Cheers and hth. - Alf
@Cheersandhth.-Alf:您是在指编译器隐式提供复制成员函数,并且在某些情况下这种做法已经被弃用了吗? - Howard Hinnant
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接