incomplete type as member of std::map

流过昼夜 提交于 2021-01-28 05:06:31

问题


I came about the same issue as described here
Can't allocate class with forward declared value in std::map member variable
in our codebase.

Hoever I also found other cases where our compiler (MSVC 2017) is able to compile this...
After fiddling around with the code I found that defining the con- & destructor in the cpp allows the files to compile.

In 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:

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

In 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?


回答1:


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. (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.)

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. It's as though you wrote inline Test::Test() {} inline Test::~Test() {} immediately following the class definition. 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. 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.

Then you complete the Incomplete type prior to defining the ctor/dtor yourself, so the Incomplete ctor/dtor invocations can be successfully compiled. If you remove the definition of Incomplete then you will run into the same error.


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.



来源:https://stackoverflow.com/questions/45718599/incomplete-type-as-member-of-stdmap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!