Reputation: 8167
g++ -std=c++11
does not compile a class that contains a container that contains unique pointers that point to a forward declared class. Questions:
Code example:
#include <vector>
#include <memory>
// variant 1 (with full class definition): compiles
class Bar { [..] };
using BarPtr = std::unique_ptr<Bar>;
// variant 2 (with shared instead of unique pointers): compiles
using BarPtr = std::shared_ptr<class Bar>;
// variant 0 (which is what we want): compilation fails below
using BarPtr = std::unique_ptr<class Bar>;
// end of variants
class Foo {
std::vector<BarPtr> vec;
public:
Foo() {} // compilation of variant 0 fails here:
// In instantiation of ‘void std::default_delete<Bar>::operator()(Bar*) const
// ...
// invalid application of ‘sizeof’ to incomplete type ‘Bar’
};
I have seen How to forward declare a class to be used in a standard container of unique_ptr and Is std::unique_ptr<T> required to know the full definition of T?, but do not find convincing answers to my above questions.
Upvotes: 3
Views: 1064
Reputation: 3571
You need to move those parts of Foo to the implementation file, that need to full definition of Bar (see table by Howard Hinnant: https://stackoverflow.com/a/6089065/2173029). Following this guideline, this compiles:
#include <vector>
#include <memory>
class Bar;
using BarPtr = std::unique_ptr<Bar>;
class Foo {
std::vector<BarPtr> vec;
public:
Foo(); // Needs Bar in implementation
~Foo();// Needs Bar in implementation
};
Upvotes: 2
Reputation: 8167
The error message at line
Foo() {};
seems to tell that a destructor ~Bar()
is required. But why? This part of my question is still open.
As for the practical solution, however, the answer is simple: Replace the above line by
Foo();
and implement Foo::Foo
in a compilation unit that sees the full definition of class Bar
.
Upvotes: 0
Reputation: 3249
The problem is that you cannot delete by pointer to incomplete (forward declared) type. Make sure the definition of Bar
is visible in the destructor of the containing class, or use a custom deleter for the unique_ptr
that sees it. See also std::unique_ptr with an incomplete type won't compile
Upvotes: 0
Reputation: 20274
You may do this:
#include <vector>
#include <memory>
class Bar;
using BarPtr = std::unique_ptr<Bar>;
class Foo {
std::vector<BarPtr> vec;
public:
Foo() {} // variant 3 fails here:
// invalid application of ‘sizeof’ to incomplete type ‘Bar’
};
//Implementation goes here
class Bar{};
int main(){
Foo a;
}
Upvotes: 0