Must destructor be just available (public) or fully valid for default initialized class members?(析构函数必须只是可用的(公共的)还是对默认的初始化类成员完全有效?)
问题描述
请考虑结构A
具有u
类型的U<R>
和默认初始值设定项。析构函数~U<R>
仅声明为:
template<typename T>
struct U {
~U();
};
struct R;
struct A {
U<R> u = U<R>{};
};
所有编译器都接受此代码,demo:https://gcc.godbolt.org/z/oqMjTovMo
但如果我们按如下方式定义析构函数~U<R>
:
template<typename T>
struct U {
~U() { static_assert( sizeof(T) > 0 ); }
};
那么当前的编译器就不同了。MSVC继续接受程序,而GCC/Clang打印错误
error: invalid application of 'sizeof' to an incomplete type 'R'
演示:https://gcc.godbolt.org/z/713TzPd6v
显然,编译器必须验证默认初始化类成员的析构函数可用性,以防在构造过程中发生异常。但是,标准是否要求编译器只检查析构函数的可用性(就像MSVC那样),或者编译器也应该验证它的主体呢?MSVC行为在这里看起来更方便,因为它允许在结构A
定义的时刻前向声明R
。
附注:这项探索不仅仅具有理论意义。如果将这里的U
替换为std::unique_ptr
,那么它解释了为什么std::unique_ptr<R>
类型的类字段被msvc接受,而被GCC/Clang拒绝,因为类R
不完整。
推荐答案
[dcl.init.aggr]/8:(强调我的)
类类型的每个元素的析构函数可能从发生聚合初始化的上下文中调用([class.dtor])。
[basic.def.odr]/8:
类的析构函数如果可能被调用,则为ODR使用。
[basic.def.odr]/10:
每个程序应包含该程序中ODR使用的ODR语句之外的每个非内联函数或变量的一个定义;不需要诊断。
因此~U()
可能在U<R> u
内部调用,这需要其定义。
然后根据[temp.inst]/4:
除非类模板或成员模板的成员是声明的专门化,否则当在要求存在成员定义的上下文中引用专门化时,该成员的专门化是隐式实例化的...
附加说明:当然,当A
的实例被销毁时,实际上是invoked。因此需要对其进行编译。
注意:在第一个版本中,编译器接受代码,因为析构函数不是内联的,所以它在链接期间失败(example)。
至于MSVC接受代码,它似乎是一个错误。
这篇关于析构函数必须只是可用的(公共的)还是对默认的初始化类成员完全有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:析构函数必须只是可用的(公共的)还是对默认的初始化类成员完全有效?
基础教程推荐
- C++ 程序在执行 std::string 分配时总是崩溃 2022-01-01
- 您如何将 CreateThread 用于属于类成员的函数? 2021-01-01
- 设计字符串本地化的最佳方法 2022-01-01
- C++,'if' 表达式中的变量声明 2021-01-01
- 什么是T&&(双与号)在 C++11 中是什么意思? 2022-11-04
- C++ 标准:取消引用 NULL 指针以获取引用? 2021-01-01
- 如何在 C++ 中处理或避免堆栈溢出 2022-01-01
- 运算符重载的基本规则和习语是什么? 2022-10-31
- 调用std::Package_TASK::Get_Future()时可能出现争用情况 2022-12-17
- 如何定义双括号/双迭代器运算符,类似于向量的向量? 2022-01-01