woh*_*tad 6 c++ constructor language-lawyer incomplete-type
下面的代码编译正常(参见下面的 Golbolt 链接):
#include <memory>
struct B;
struct A1 {
A1() = default;
~A1();
std::unique_ptr<B> ptr;
};
#if 0
struct A2 {
A2();
~A2();
std::unique_ptr<B> ptr;
};
A2::A2() = default;
#endif
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
但如果我用 替换#if 0来#if 1编译类,A2我会从 gcc 收到以下错误:
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/memory:76,
from <source>:1:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:396:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]'
<source>:17:1: required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:93:23: error: invalid application of 'sizeof' to incomplete type 'B'
93 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
ASM generation compiler returned: 1
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/memory:76,
from <source>:1:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:396:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]'
<source>:17:1: required from here
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:93:23: error: invalid application of 'sizeof' to incomplete type 'B'
93 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
Execution build compiler returned: 1
Run Code Online (Sandbox Code Playgroud)
我在 MSVC 上得到了类似的结果。
无论我编译为 C++17 还是 C++20,我都会得到这个结果。
我的问题:和
之间的唯一区别是类定义内部或外部的构造函数的定义(在这两种情况下它都定义为)。
为何本案有差异?A1A2default
这个问题是这篇文章的后续问题:为什么 unique_ptr 需要构造函数中的完整类型?
区别如下:在 中A1,默认构造函数在其第一个声明中被默认,编译器在需要其定义之前实际上不会定义它,并且由于您在任何时候都不会真正尝试创建对象A1,因此默认构造函数的定义永远不会在此翻译单元中需要,因此编译器永远不会生成定义。至于A2,超出范围的定义
A2::A2() = default;
Run Code Online (Sandbox Code Playgroud)
实际上为它出现的函数生成一个定义。到那时,B一定是完整的,但事实并非如此。这在链接的问题中进行了解释。
[...] 如果函数是用户声明的并且在第一次声明时未显式默认或删除,则该函数是用户提供的。用户提供的显式默认函数(即,在第一次声明后显式默认)在显式默认时隐式定义;如果这样的函数被隐式定义为已删除,则该程序是错误的。未定义为已删除的非用户提供的默认函数(即在类中隐式声明或显式默认)在使用 odr ([basic.def.odr]) 或需要常量求值 ([表达式.const])。
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |