Reputation: 457
I have written a program in C++ that compiles with clang++ but not with g++ and I would like to understand why.
The essential part is this:
class Table {
private:
...
std::unordered_map<std::string,Table> table_map;
...
};
I thought that std::unordered_map would be using pointers "under the hood", so that this is legal. I'm not declaring a Table inside of a Table, but I'm creating a container that has pointer(s) to Table(s) inside of a Table. Or so I thought. Clang++ has no problem with this and the program runs fine.
However, g++ complains about this, saying "note: forward declaration of 'class Table'
". This suggests I should explicitly make the std::unordered_map take a pointer (std::unordered_map<std::string,Table*>
, or perhaps some flavor of smart pointer). That requires I do some extra work (and I'm dealing with code I wrote over a year ago, so I'm not eager to have to figure out what I did in order to make the necessary changes).
Is this a bug in g++ or is clang++ doing something clever that's not really part of the standard? Is there a better way to rewrite this code so that it compiles on both clang++ and g++?
I have another class called Value, and there's a std::unordered_map of Values within Table, so would I get around this problem by creating a superclass Element from which Value and Table both inherit, and then having Table contain a std::unordered_map<std::string,Element>
? Or would such a map be unable to store Values and Tables because it was declared for Elements?
Upvotes: 2
Views: 135
Reputation: 141618
This is undefined behaviour. Standard library containers may not be instantiated with incomplete types, unless it explicitly says that the container supports it (e.g. unique_ptr
).
Your options are:
Upvotes: 2
Reputation: 29724
The error is caused by std::unordered_map having to rehash the table and then copying of elements. The value stored in container must therefore be a complete type.
You can get over it by wrapping value into smart pointers:
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory> // shared_ptr
class Table {
private:
std::unordered_map<std::string, std::shared_ptr<Table> > t;
};
int main() {
Table t;
return 0;
}
Upvotes: 4