我遇到了与此处所述相同的问题
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();
}
答案 0 :(得分:2)
这是因为声明类成员不需要Incomplete
完成,但调用std::map
析构函数,因为它必然需要调用{{1析构函数来销毁地图内容。 (调用默认的Incomplete
构造函数可以要求类型完成,具体取决于实现。我不确定规范是否对此提出任何要求。我至少可以想到一个不需要完整类型的实现。)
如果您依赖编译器为您生成隐式ctors / dtors,这意味着在遇到类定义时类型必须完整,因为那时编译器将隐式生成ctor和dtor。就像你在类定义之后立即写std::map
一样。 dtor隐含地破坏地图,这将通过在任何存储的值上调用inline Test::Test() {} inline Test::~Test() {}
来破坏地图内容,如果没有~Incomplete()
的定义,我们就无法做到这一点。在那里,整个事情崩溃了,你得到一个错误。
但是,如果你告诉编译器(通过Incomplete
ctor / dtor声明)你将在以后实现它们,那么它将不会生成它们,因此没有Test
ctor / dtor调用在那时被编译。
然后在自己定义ctor / dtor之前完成std::map
类型,以便{<1}} ctor / dtor invocations 可以成功编译。如果删除Incomplete
的定义,则会遇到相同的错误。
请注意,正如其他人所说,您可以通过在地图中存储指向不完整类型的指针/引用来解决此问题。指向不完整类型的指针或引用实际上本身就是一个完整类型。然而,在所有情况下这可能都不可取,所以我在不知道有关如何使用地图的更多细节的情况下推动该解决方案犹豫不决。