Now first, I am aware of the general issues with unique_ptr<> and forward declarations as in Forward declaration with unique_ptr? .
Consider these three files:
A.h
#include <memory>
#include <vector>
class B;
class A
{
public:
~A();
private:
std::unique_ptr<B> m_tilesets;
};
C.cpp
#include "A.h"
class B {
};
A::~A() {
}
main.cpp
#include <memory>
#include "A.h"
int main() {
std::unique_ptr<A> m_result(new A());
}
Issuing g++ -std=c++11 main.cpp C.cpp
yields the following error:
In file included from /usr/include/c++/4.8/memory:81:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]’:
/usr/include/c++/4.8/bits/unique_ptr.h:184:16: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]’
A.h:6:7: required from here
/usr/include/c++/4.8/bits/unique_ptr.h:65:22: error: invalid application of ‘sizeof’ to incomplete type ‘B’
static_assert(sizeof(_Tp)>0,
That's true, B is an incomplete type in line 6 of A.h - but that's not where A's destructor is! g++ seems to generate a destructor for A even though I am providing one. A's destructor is in C.cpp line 7 and there B is a perfectly defined type. Why am I getting this error?
Forward Declaration refers to the beforehand declaration of the syntax or signature of an identifier, variable, function, class, etc. prior to its usage (done later in the program). Example: // Forward Declaration of the sum() void sum(int, int); // Usage of the sum void sum(int a, int b) { // Body }
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier. In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function's body.
You also need to put A's constructor in C.cpp:
A.h
#include <memory>
#include <vector>
class B;
class A {
public:
A();
~A();
private:
std::unique_ptr<B> m_tilesets;
};
C.cpp
#include "A.h"
class B {
};
A::~A() {
}
A::A() {
}
See this answer. The constructor needs access to the complete type as well. This is so that it can call the deleter if an exception is thrown during construction.
The implicitly defined special member functions are inline, leading to issues with incomplete types. As the link from Chris's answer shows, all non-delegating constructors could potentially invoke the destructor. This includes copy(deleted in this case) and move constructors as well. So, when you are dealing with non-static members involving incomplete types, explicitly default the definitions in the source file, thus ensuring that they aren't defined inline.
In header:
A();
~A();
A(const A&);
A(A&&);
In source:
A::A() = default;
A::~A() = default;
A::A(const A&) = default;
A::A(A&&) = default;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With