c++ - 作为 std::map 成员的不完整类型

标签 c++ stdmap incomplete-type

我遇到了与此处描述的相同的问题
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/

相关文章:

c++ - 从迭代器更改 std::map 中的值

c++ - 使用不完整类型的函数模板实例化

C - 取消引用指向不完整类型的指针 - 将字符串插入二叉搜索树

c++ - 我应该如何在文本角色扮演游戏中调用玩家法术?

c++ - 我的 List 类如何包含所有类型?

c++ - 将 int 转换为 const wchar_t*

c++ - 跨多个对象使用 map

c++ - 从 ‘const type*’ 到 ‘type*’ 的无效转换

c++ - GUID 作为 std::map 键

c++ - 实例化类时出现不完整的类型错误