非默认析构函数会导致不完整的类型错误
Not default destructor causes incomplete type error
这个例子显示了编译器(msvc14,gcc,clang(的奇怪行为,但我没有找到解释。
当我们实现 pipml 习语并使用前向声明时,我们需要考虑unique_ptr具有自己的不完整类型的特定行为。 这里和这里都提到了这种情况。
但是,当我们将转发类的定义移动到另一个头文件并在稍后使用客户端类时将标头包含在一个地方时,编译器变得疯狂 - 在析构函数声明的某些特殊情况下,他们说不完整的类型。
下面是一个最小示例。如果取消注释"#define CASE_2"或"#define CASE_3"并尝试构建它,则会出现编译错误。
文件 foo.h
#ifndef FOO_H
#define FOO_H
class Foo{};
#endif // FOO_H
文件库.h
#ifndef BASE_H
#define BASE_H
#include <memory>
//#define CASE_1
//#define CASE_2
//#define CASE_3
class Foo;
class Base
{
public:
#if defined(CASE_1)
~Base() = default; // OK!
#elif defined(CASE_2)
~Base() {}; // error: invalid application of 'sizeof' to incomplete type 'Foo'
#elif defined(CASE_3)
~Base(); // error: invalid application of 'sizeof' to incomplete type 'Foo'
#endif
// OK!
private:
std::unique_ptr<Foo> m_foo;
};
#endif // BASE_H
文件库.cpp
#include "base.h"
#if defined(CASE_3)
Base::~Base()
{
}
#endif
文件主.cpp
#include "foo.h" // No matter order of this includes
#include "base.h" //
int main()
{
Base b;
}
我相信,这与C++标准12.4/6有关。
默认且未定义为已删除的析构函数是 当它被 ODR 使用 (3.2( 来销毁 它的类类型 (3.7( 或在其之后显式默认时 第一次声明。
当您将析构函数设置为默认值时,它只会在使用 ODR时定义,即当Base
对象被销毁时。在您的代码片段中,不会销毁这种类型的对象,因此,程序编译 - 因为实际上并没有在任何地方调用unique_ptr的删除器 - 它仅由Base
析构函数调用,在这种情况下未定义。
提供用户定义的析构函数时,该析构函数是就地定义的,程序将变得格式不正确,因为您无法销毁不完整类型的unique_ptr
对象。
顺便说一下,具有析构函数declared
,但不defined
(如~base();
(不会产生编译错误,原因相同。
但是,当我们将转发类的定义移动到另一个头文件并在稍后使用客户端类时将标头包含在一个地方时,编译器变得疯狂 - 在一些析构函数声明的特殊情况下,他们说不完整的类型。
编译器很好,当定义B
的析构函数时,类Foo
的定义也必须是可见的。这发生在CASE_1中 - 在main.cpp
中定义的析构函数,并且您在那里包含foo.h
。无论如何CASE_2都不会编译,也不应该使用。当您包含来自base.cpp
的foo.h
时,CASE_3 将编译,无论如何您都应该这样做并使用这种情况(并且不包括来自 main 的foo.h
.cpp否则您将破坏 pimpl 习语的全部目的(。
所以编译器没有奇怪的行为,你对疙瘩成语的使用很奇怪,这会导致你观察到的行为。
- 类没有命名C++代码中的类型错误
- 不完整类型错误(E0409、E0070、E0515)
- 使用具有结构不完整类型错误的模板
- 不命名构造函数和析构函数上的类型错误
- 返回派生类型时出现协变类型错误
- 为什么此构造函数没有给出不完整的类型错误?
- 定义模板化结构的特征时出现不完整的类型错误
- 使用重载构造函数时出现不完整的类型错误
- 为什么我得到表达式必须有类类型错误?
- 输出 [left]=input[i] 行中的 c++ 代码中存在无效的类型错误
- 枚举成员不是类型错误
- 如何修复"ctypes"。参数错误:参数 2:<键入"异常.类型错误">:RaspberryPi 中的错误类型"错误
- 外部 "C" Visual Studio 2015 中的显式类型错误,DLL 测试代码
- 非默认析构函数会导致不完整的类型错误
- 为什么按引用传入会导致绑定引用类型错误
- Objective-C C++ 包装器 类型错误的不完整定义
- 输入类型错误
- 当构造函数的参数类型错误时引发异常
- 命名空间中的'bad_cast' 'std' 未命名类型错误
- C UNWORKOWN类型错误