Search code examples
c++compiler-errorsforward-declarationstdmap

Can't allocate class with forward declared value in std::map member variable


In 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

In test.cpp:

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

In main.cpp

#include "test.h"

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

g++ 4.7 gives me an error that struct Incomplete is forward declared when I write g++ main.cpp test.h -o main.o.

However, if I change std::map<int, Incomplete> member to std::map<int, Incomplete*> member, main.o compiles. Why is this?


Solution

  • Note: as of C++11, the explanation below is outdated: standard library containers now work with incomplete types.


    Why is this?

    Because the C++ standard library containers are not defined to work with incomplete member types. This is by design1 – but it’s arguably an error (and might be changed in future versions of C++). The Boost.Containers library fixes this.

    Your code with pointers works because a pointer to an incomplete type is itself a complete type. However, this obviously changes the semantics of your type quite drastically (in particular, who manages the memory?) and it’s generally not a good idea to use this as a replacement.


    1 It’s worth pointing out that the article claims that you technically cannot implement std::map to work with incomplete types. However, this claim is wrong.