简体   繁体   English

类型不完整的std :: map成员

[英]incomplete type as member of std::map

I came about the same issue as described here 我遇到了与此处所述相同的问题
Can't allocate class with forward declared value in std::map member variable 无法在std :: map成员变量中分配具有正向声明值的类
in our codebase. 在我们的代码库中。

Hoever I also found other cases where our compiler (MSVC 2017) is able to compile this... 但是,我还发现了其他情况,我们的编译器(MSVC 2017)能够对此进行编译...
After fiddling around with the code I found that defining the con- & destructor in the cpp allows the files to compile. 摆弄代码后,我发现在cpp中定义con-和destructor可以编译文件。

In test.h : 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

In test.cpp : test.cpp

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

In main.cpp : main.cpp

#include "test.h"

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

Why does defining the con- & destructor in the cpp file allow member-std::map-variables to use incomplete types? 为什么在cpp文件中定义con-和destructor允许member-std :: map-variables使用不完整的类型?

This is because declaring the class member does not require Incomplete to be complete, but invoking the std::map destructor does , because it necessarily needs to invoke the Incomplete destructor to destroy the map contents. 这是因为声明类成员并不需要Incomplete来完成,而是调用std::map析构函数则需Incomplete ,因为它必须调用Incomplete析构函数来销毁映射内容。 (Invoking the default std::map constructor could require the type to be complete, depending on the implementation. I'm not sure if the spec puts any requirements on this. I can think of at least one implementation that would not require complete types.) (根据实现的不同,调用默认的std::map构造函数可能需要完整的类型。我不确定规范是否对此有任何要求。我可以考虑至少一个不需要完整类型的实现。 。)

If you rely on the compiler to generate implicit ctors/dtors for you, that means that the type must be complete when the class definition is encountered, because that's when the compiler is going to implicitly generate the ctor and dtor. 如果您依赖编译器为您生成隐式ctor / dtor,则这意味着在遇到类定义时类型必须完整,因为那是编译器将隐式生成ctor和dtor的时间。 It's as though you wrote inline Test::Test() {} inline Test::~Test() {} immediately following the class definition. 就像您在类定义之后立即编写了inline Test::Test() {} inline Test::~Test() {} The dtor is implicitly going to destroy the map, which is going to destroy the map contents by calling ~Incomplete() on any stored values, which we can't do without a definition for Incomplete . dtor隐式要破坏地图,这将通过在任何存储的值上调用〜Incomplete ~Incomplete()来破坏地图内容,如果没有Incomplete的定义,我们将无法做到。 And there, the whole thing falls apart and you get an error. 在那里,整个事情崩溃了,您会得到一个错误。

However, if you tell the compiler (by way of the Test ctor/dtor declarations) that you will be implementing them later, then it won't generate them, therefore no std::map ctor/dtor invocation gets compiled at that point. 但是,如果你告诉编译器(通过的方式Test将在以后执行这些构造函数/析构函数的声明),那么就不会产生它们,因此没有std::map构造函数/析构函数调用得到在这一点上进行编译。

Then you complete the Incomplete type prior to defining the ctor/dtor yourself, so the Incomplete ctor/dtor invocations can be successfully compiled. 然后,您在自己定义ctor / dtor之前先完成Incomplete类型,这样可以成功地编译Incomplete ctor / dtor调用。 If you remove the definition of Incomplete then you will run into the same error. 如果删除Incomplete的定义,则会遇到相同的错误。


Note that, as others have said, you can side-step this issue by storing pointers/references to the incomplete type in the map instead. 请注意,正如其他人所说的,您可以通过在映射中存储指向不完整类型的指针/引用来避开此问题。 A pointer or reference to an incomplete type is actually itself a complete type. 指向不完整类型的指针或引用实际上本身就是完整类型。 However, this may not be desirable in all cases so I'm hesitant to push that solution without knowing more details about how the map will be used. 但是,这并非在所有情况下都是理想的,因此我在不了解有关如何使用地图的更多细节的情况下犹豫不决地提出该解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM