【发布时间】:2018-01-01 20:18:57
【问题描述】:
这个例子显示了编译器(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;
}
【问题讨论】:
-
不确定,但我认为编译器实际上并没有抱怨析构函数,而是抱怨在声明非默认析构函数时缺少的默认构造函数
-
CASE_3如果您包含 base.cpp 中的 foo.h,则编译得很好,无论如何您都应该这样做。如果你不包含 main.cpp 中的 foo.h,CASE_1将不会编译,这是你不应该做的。
标签: c++ gcc destructor incomplete-type