类能否无析构函数?该模板代码中各编译器谁符合C++标准?
类是否可以不具备析构函数?C++标准与编译器行为分析
问题背景
是否存在C++类可以不具备析构函数(即不可销毁)?以下示例代码引发了不同编译器的分歧:
#include <type_traits> template <typename T> struct A { ~A() requires(std::is_void_v<T>); //~A() requires(!std::is_void_v<T>) = default; }; template struct A<int>;
编译器行为差异
- GCC 13.2:编译通过,认为
A<int>存在有效析构函数 - Clang 17.0:报错:
error: no viable destructor found for class 'A<int>' - MSVC 19.38:报错:
error C7653: 'A<int>': failed to select a destructor for the class
添加被注释的代码行(~A() requires(!std::is_void_v<T>) = default;)后,所有编译器均可正常编译。
正确行为与标准依据
Clang和MSVC的行为符合C++标准,GCC存在不符合标准的实现。
根据C++标准[class.dtor]章节的规定:
- 若类中显式声明了任意析构函数(包括带约束的析构函数),编译器不会隐式生成默认析构函数。
- 对于模板特化
A<int>,声明的析构函数~A() requires(std::is_void_v<T>)因约束std::is_void_v<int>为false而不可用。此时由于已有显式声明的析构函数,编译器不会自动补充生成默认析构函数,导致A<int>没有可用的析构函数,程序属于格式错误。
当添加带反向约束的默认析构函数后,A<int>特化会匹配到~A() requires(!std::is_void_v<T>) = default;,该析构函数约束满足且为默认生成的有效析构函数,因此解决了无可用析构函数的问题。
GCC的错误在于,它在已有显式声明析构函数(即使该析构函数因约束不可用)的情况下,仍然隐式生成了默认析构函数,这违反了标准中“显式声明析构函数则禁止隐式生成”的规则。
内容的提问来源于stack exchange,提问作者Cassio Neri
相关产品推荐
相关产品推荐

