【问题标题】:Can't allocate class with forward declared value in std::map member variable无法在 std::map 成员变量中分配具有前向声明值的类
【发布时间】:2023-03-17 09:23:02
【问题描述】:

test.h:

#ifndef TEST_H
#define TEST_H

#include <map>
struct Incomplete;

class Test {
     std::map<int, Incomplete> member;
public:
    Test();
    int foo() { return 0; }
};

#endif

test.cpp:

#include "test.h"
struct Incomplete {};
Test::Test() {}

main.cpp

#include "test.h"

int main() {
    Test test;
    return test.foo();
}

g++ 4.7 给我一个错误,当我写 g++ main.cpp test.h -o main.o 时,struct Incomplete 是前向声明的。

但是,如果我将 std::map&lt;int, Incomplete&gt; member 更改为 std::map&lt;int, Incomplete*&gt; membermain.o 将编译。为什么是这样?

【问题讨论】:

    标签: c++ compiler-errors forward-declaration stdmap


    【解决方案1】:

    注意:从 C++11 开始,以下解释已过时:标准库容器现在可以处理不完整的类型。


    这是为什么?

    因为 C++ 标准库容器未定义为使用不完整的成员类型。 This is by design1——但它可以说是一个错误(并且可能会在未来的 C++ 版本中更改)。 Boost.Containers 库修复了这个问题。

    您的带有指针的代码可以工作,因为指向不完整类型的指针本身就是完整类型。但是,这显然会极大地改变您的类型的语义(特别是,谁管理内存?),使用它作为替代通常不是一个好主意。


    1 值得指出的是,这篇文章声称您在技术上无法实现std::map 来处理不完整的类型。但是,这种说法是错误的。

    【讨论】:

    • 这似乎已经过时了,至少从 C++11 开始——模板参数不是不完整类的所有要求似乎都已被删除。
    【解决方案2】:

    当您转发声明一个类型时,您基本上声明了具有该名称的类型存在,仅此而已。编译器不知道它的大小、成员等。它被称为不完整类型,只能用于声明指针或引用。这是可能的,因为指针的大小,无论其类型在同一平台上都是相同的。

    【讨论】:

      【解决方案3】:

      前向声明意味着“这个类/结构/以后将在代码中的任何内容”。该容器需要知道结构有多大才能进行内存簿记。用技术术语来说,您使用的是不完整类型

      由于指针在大多数机器上是固定大小的(x64 通常有 8 个字节的指针),因此您不需要在编译时查看结构的完整定义,因为您不需要“计算”多少在地图中为该结构保留的空间:您只需要指针所需的空间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-04
        • 2021-10-08
        相关资源
        最近更新 更多