我遇到了与此处描述的相同的问题
Can't allocate class with forward declared value in std::map member variable
在我们的代码库中。
然而,我还发现了其他情况,我们的编译器(MSVC 2017)能够编译此...
在摆弄代码后,我发现在 cpp 中定义构造函数和析构函数允许文件编译。
在test.h
中:
#ifndef TEST_H
#define TEST_H
#include <map>
struct Incomplete;
class Test {
std::map<int, Incomplete> member;
public:
Test();
~Test();
int foo() { return 0; }
};
#endif
在test.cpp
中:
#include "test.h"
struct Incomplete {};
Test::Test() {}
Test::~Test() {}
在main.cpp
中:
#include "test.h"
int main()
{
Test test;
return test.foo();
}
为什么在 cpp 文件中定义构造函数和析构函数允许 member-std::map-variables 使用不完整类型?
最佳答案
这是因为声明类成员不需要 Incomplete
来完成,但调用 std::map
析构函数则需要,因为它必然需要调用 Incomplete
析构函数来销毁映射内容。 (调用默认的 std::map
构造函数可能要求类型完整,具体取决于实现。我不确定规范是否对此提出任何要求。我可以想到至少一种实现不需要完整的类型。)
如果您依赖编译器为您生成隐式 ctor/dtor,则意味着遇到类定义时类型必须完整,因为此时编译器将隐式生成 ctor 和 dtor。就好像您在类定义之后立即写入了 inline Test::Test() {} inline Test::~Test() {}
一样。 dtor 会隐式地销毁映射,这将通过对任何存储的值调用 ~Incomplete()
来销毁映射内容,如果没有 Incomplete
的定义,我们就无法做到这一点。到了这里,整个事情就崩溃了,你会得到一个错误。
但是,如果您告诉编译器(通过 Test
ctor/dtor 声明)您稍后将实现它们,那么它不会生成它们,因此不会生成 std::map
ctor/dtor此时调用将被编译。
然后,您在自己定义 ctor/dtor 之前完成 Incomplete
类型,以便可以成功编译 Incomplete
ctor/dtor 调用。如果您删除 Incomplete
的定义,那么您将遇到相同的错误。
请注意,正如其他人所说,您可以通过在映射中存储对不完整类型的指针/引用来回避此问题。指向不完整类型的指针或引用实际上本身就是完整类型。但是,这可能并不适用于所有情况,因此在不了解有关如何使用 map 的更多详细信息的情况下,我对插入该解决方案犹豫不决。
关于c++ - 作为 std::map 成员的不完整类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45718599/