这个例子显示编译器(msvc14,gcc,clang)的奇怪行为,但是我没有找到解释。不是默认的析构函数导致不完整的类型错误
当我们实现pipml习语并使用前向声明时,我们需要考虑unique_ptr具有自己的具有不完整类型的特定行为。 这种情况被提及here和here。
但是,当我们将转发类的定义移动到另一个头文件并在稍后使用客户类时在一个地方包含头文件时,编译器变得疯狂 - 在某些特殊的析构函数声明中,他们说关于不完整类型。
这是一个简单的例子。如果取消注释“#define CASE_2”或“#define CASE_3”并尝试构建它,则会出现编译错误。
文件foo.h中
#ifndef FOO_H
#define FOO_H
class Foo{};
#endif // FOO_H
文件base.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
文件base.cpp
#include "base.h"
#if defined(CASE_3)
Base::~Base()
{
}
#endif
文件main.cpp中
#include "foo.h" // No matter order of this includes
#include "base.h" //
int main()
{
Base b;
}
不确定,但我认为编译器实际上并没有抱怨析构函数,而是关于默认的构造函数,如果你声明了非默认的析构函数,则缺少 – user463035818
如果你从基地包含foo.h,CASE_3编译得很好。 CPP,无论如何,你应该这样做。如果你不包含main.cpp中的foo.h,那么'CASE_1'不会编译,你不应该这样做。 – Slava