This is not a dupe of std::unique_ptr with an incomplete type won't compile.
Consider the code below:
#include <memory>
struct X
{
X();
~X();
struct Impl;
std::unique_ptr<Impl> up_;
};
struct Impl {}; // fully visible here
X::X() : up_{nullptr}{}
X::~X() = default;
int main()
{
X x;
}
Live on Coliru
gcc/clang both spit an error saying that Impl is incomplete. However, I provide a default destructor for X after Impl is fully visible, so IMO the code should compile. Why doesn't? Now comes the surprise: If I make Impl an inner class, i.e. define
struct X::Impl{};
instead, then the code compiles, even without providing a destructor. Why is this happening? Shouldn't we provide such a default destructor, at least according to the link mentioned in the first line?
You have two different structs named Impl.
struct X
{
struct Impl; // Here you declare X::Impl
std::unique_ptr<Impl> up_; // Here you create a pointer to a X::Impl
};
struct Impl {}; // Here you declare and define ::Impl
...
int main()
{
X x; // Here X::Impl is still incomplete
}
Related
I want to use unique_ptr with an incomplete type. The code below does what I expected and can't compile.
#include <memory>
struct bar;
struct foo {
foo() {
}
~foo() {
}
std::unique_ptr<bar> pb{};
};
int main() {
foo f;
}
However, if I add the definition of bar after the function main's definition. It can compile.
#include <memory>
struct bar;
struct foo {
foo() {
}
~foo() {
}
std::unique_ptr<bar> pb{};
};
int main() {
foo f;
}
struct bar {
};
I have no idea why the definition after main can help main compile. Is that behavior defined in c++ standard?
The first program is ill-formed. The second program is ill-formed, no diagnostic required.
std::unique_ptr does allow instantiation with an incomplete type, which is why using it as a member in foo is ok.
However both the definitions of the constructor and destructor of foo potentially invoke the destructor of pb which in turn invokes the default deleter std::default_delete<bar>. This requires bar to be a complete type.
This means you must make bar complete before you define the two functions. So you need to define them outside the class and put the definition of bar before both of these definitions:
#include <memory>
struct bar;
struct foo {
foo();
~foo();
std::unique_ptr<bar> pb{};
};
struct bar {
};
foo::foo() { }
foo::~foo() { }
int main() {
foo f;
}
In the first program the default deleter's operator() will be implicitly instantiated, but bar will be incomplete at all possible points-of-instantiation, so that the compiler is required to diagnose the issue, e.g. with an error message.
In the second program, there is a possible point-of-instantiation at the end of the translation unit (in addition to the point explained above) where bar is complete. A diagnostic is not required if two possible points-of-instantiation would give different results.
I have a class foo that derives from base, and hence have a virtual destructor. Class foo implements the pimpl idiom with a std::unique_ptr of the incomplete type foo::impl.
Like you can see in the code below, it doesn't compile as expected if I try to delete a foo instance because std::unique_ptr needs to know foo::impl. On the other hand, it does compile when I delete it through its base class. I don't understand why it does so and more importantly I would like to know if it is undefined behavior.
// Header.h
#pragma once
#include <memory>
class Base
{
public:
virtual ~Base() =default;
};
class foo: public Base
{
public:
foo();
private:
class impl;
std::unique_ptr<impl> p_;
};
// Source.cpp
#include "Header.h"
class foo::impl
{
};
foo::foo():p_(std::make_unique<foo::impl>()) {};
// main.cpp
#include "Header.h"
int main()
{
std::unique_ptr<Base> t = std::make_unique<foo>(); // this one compiles and links and I would have expected it not to.
//foo b; // this one does not compile as expected
return 1;
}
I have the same results with Visual Studio 2013 and Visual Studio 2017.
I'm using the pimpl-idiom with std::unique_ptr:
class window {
window(const rectangle& rect);
private:
class window_impl; // defined elsewhere
std::unique_ptr<window_impl> impl_; // won't compile
};
However, I get a compile error regarding the use of an incomplete type, on line 304 in <memory>:
Invalid application of 'sizeof' to an incomplete type 'uixx::window::window_impl'
For as far as I know, std::unique_ptr should be able to be used with an incomplete type. Is this a bug in libc++ or am I doing something wrong here?
Here are some examples of std::unique_ptr with incomplete types. The problem lies in destruction.
If you use pimpl with unique_ptr, you need to declare a destructor:
class foo
{
class impl;
std::unique_ptr<impl> impl_;
public:
foo(); // You may need a def. constructor to be defined elsewhere
~foo(); // Implement (with {}, or with = default;) where impl is complete
};
because otherwise the compiler generates a default one, and it needs a complete declaration of foo::impl for this.
If you have template constructors, then you're screwed, even if you don't construct the impl_ member:
template <typename T>
foo::foo(T bar)
{
// Here the compiler needs to know how to
// destroy impl_ in case an exception is
// thrown !
}
At namespace scope, using unique_ptr will not work either:
class impl;
std::unique_ptr<impl> impl_;
since the compiler must know here how to destroy this static duration object. A workaround is:
class impl;
struct ptr_impl : std::unique_ptr<impl>
{
~ptr_impl(); // Implement (empty body) elsewhere
} impl_;
As Alexandre C. mentioned, the problem comes down to window's destructor being implicitly defined in places where the type of window_impl is still incomplete. In addition to his solutions, another workaround that I've used is to declare a Deleter functor in the header:
// Foo.h
class FooImpl;
struct FooImplDeleter
{
void operator()(FooImpl *p);
};
class Foo
{
...
private:
std::unique_ptr<FooImpl, FooImplDeleter> impl_;
};
// Foo.cpp
...
void FooImplDeleter::operator()(FooImpl *p)
{
delete p;
}
Note that using a custom Deleter function precludes the use of std::make_unique (available from C++14), as already discussed here.
use a custom deleter
The problem is that unique_ptr<T> must call the destructor T::~T() in its own destructor, its move assignment operator, and unique_ptr::reset() member function (only). However, these must be called (implicitly or explicitly) in several PIMPL situations (already in the outer class's destructor and move assignment operator).
As already pointed out in another answer, one way to avoid that is to move all operations that require unique_ptr::~unique_ptr(), unique_ptr::operator=(unique_ptr&&), and unique_ptr::reset() into the source file where the pimpl helper class is actually defined.
However, this is rather inconvenient and defies the very point of the pimpl idoim to some degree. A much cleaner solution that avoids all that is to use a custom deleter and only move its definition into the source file where the pimple helper class lives. Here is a simple example:
// file.h
class foo
{
struct pimpl;
struct pimpl_deleter { void operator()(pimpl*) const; };
std::unique_ptr<pimpl,pimpl_deleter> m_pimpl;
public:
foo(some data);
foo(foo&&) = default; // no need to define this in file.cc
foo&operator=(foo&&) = default; // no need to define this in file.cc
//foo::~foo() auto-generated: no need to define this in file.cc
};
// file.cc
struct foo::pimpl
{
// lots of complicated code
};
void foo::pimpl_deleter::operator()(foo::pimpl*ptr) const { delete ptr; }
Instead of a separate deleter class, you can also use a free function or static member of foo:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
using deleter = void(&)(pimpl*);
std::unique_ptr<pimpl,deleter> m_pimpl;
public:
foo(some data);
};
Probably you have some function bodies within .h file within class that uses incomplete type.
Make sure that within your .h for class window you have only function declaration. All function bodies for window must be in .cpp file. And for window_impl as well...
Btw, you have to explicitly add destructor declaration for windows class in your .h file.
But you CANNOT put empty dtor body in you header file:
class window {
virtual ~window() {};
}
Must be just a declaration:
class window {
virtual ~window();
}
To add to the other's replies about the custom deleter, in our internal "utilities library" I added a helper header to implement this common pattern (std::unique_ptr of an incomplete type, known only to some of the TU to e.g. avoid long compile times or to provide just an opaque handle to clients).
It provides the common scaffolding for this pattern: a custom deleter class that invokes an externally-defined deleter function, a type alias for a unique_ptr with this deleter class, and a macro to declare the deleter function in a TU that has a complete definition of the type. I think that this has some general usefulness, so here it is:
#ifndef CZU_UNIQUE_OPAQUE_HPP
#define CZU_UNIQUE_OPAQUE_HPP
#include <memory>
/**
Helper to define a `std::unique_ptr` that works just with a forward
declaration
The "regular" `std::unique_ptr<T>` requires the full definition of `T` to be
available, as it has to emit calls to `delete` in every TU that may use it.
A workaround to this problem is to have a `std::unique_ptr` with a custom
deleter, which is defined in a TU that knows the full definition of `T`.
This header standardizes and generalizes this trick. The usage is quite
simple:
- everywhere you would have used `std::unique_ptr<T>`, use
`czu::unique_opaque<T>`; it will work just fine with `T` being a forward
declaration;
- in a TU that knows the full definition of `T`, at top level invoke the
macro `CZU_DEFINE_OPAQUE_DELETER`; it will define the custom deleter used
by `czu::unique_opaque<T>`
*/
namespace czu {
template<typename T>
struct opaque_deleter {
void operator()(T *it) {
void opaque_deleter_hook(T *);
opaque_deleter_hook(it);
}
};
template<typename T>
using unique_opaque = std::unique_ptr<T, opaque_deleter<T>>;
}
/// Call at top level in a C++ file to enable type %T to be used in an %unique_opaque<T>
#define CZU_DEFINE_OPAQUE_DELETER(T) namespace czu { void opaque_deleter_hook(T *it) { delete it; } }
#endif
May be not a best solution, but sometimes you may use shared_ptr instead.
If course it's a bit an overkill, but... as for unique_ptr, I'll perhaps wait 10 years more until C++ standard makers will decide to use lambda as a deleter.
Another side.
Per your code it may happen, that on destruction stage window_impl will be incomplete. This could be a reason of undefined behaviour.
See this:
Why, really, deleting an incomplete type is undefined behaviour?
So, if possible I would define a very base object to all your objects, with virtual destructor. And you're almost good. You just should keep in mind that system will call virtual destructor for your pointer, so you should define it for every ancestor. You should also define base class in inheritance section as a virtual (see this for details).
Using extern template
The issue with using std::unique_ptr<T> where T is an incomplete type is that unique_ptr needs to be able to delete an instance of T for various operations. The class unique_ptr uses std::default_delete<T> to delete the instance. Hence, in an ideal world, we would just write
extern template class std::default_delete<T>;
to prevent std::default_delete<T> from being instantiated. Then, declaring
template class std::default_delete<T>;
at a place where T is complete, would instantiate the template.
The issue here is that default_delete actually defines inline methods that will not be instantiated. So, this idea does not work. We can, however, work around this problem.
First, let us define a deleter that does not inline the call operator.
/* --- opaque_ptr.hpp ------------------------------------------------------- */
#ifndef OPAQUE_PTR_HPP_
#define OPAQUE_PTR_HPP_
#include <memory>
template <typename T>
class opaque_delete {
public:
void operator() (T* ptr);
};
// Do not move this method into opaque_delete, or it will be inlined!
template <typename T>
void opaque_delete<T>::operator() (T* ptr) {
std::default_delete<T>()(ptr);
}
Furthermore, for ease of use, define a type opaque_ptr which combines unique_ptr with opaque_delete, and analogously to std::make_unique, we define make_opaque.
/* --- opaque_ptr.hpp cont. ------------------------------------------------- */
template <typename T>
using opaque_ptr = std::unique_ptr<T, opaque_delete<T>>;
template<typename T, typename... Args>
inline opaque_ptr<T> make_opaque(Args&&... args)
{
return opaque_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
The type opaque_delete can now be used with the extern template construction. Here is an example.
/* --- foo.hpp -------------------------------------------------------------- */
#ifndef FOO_HPP_
#define FOO_HPP_
#include "opaque_ptr.hpp"
class Foo {
public:
Foo(int n);
void print();
private:
struct Impl;
opaque_ptr<Impl> m_ptr;
};
// Do not instantiate opaque_delete.
extern template class opaque_delete<Foo::Impl>;
#endif
Since we prevent opaque_delete from being instantiated this code compiles without errors. To make the linker happy, we instantiate opaque_delete in our foo.cpp.
/* --- foo.cpp -------------------------------------------------------------- */
#include "foo.hpp"
#include <iostream>
struct Foo::Impl {
int n;
};
// Force instantiation of opaque_delete.
template class opaque_delete<Foo::Impl>;
The remaining methods could be implemented as follows.
/* --- foo.cpp cont. -------------------------------------------------------- */
Foo::Foo(int n)
: m_ptr(new Impl)
{
m_ptr->n = n;
}
void Foo::print() {
std::cout << "n = " << m_ptr->n << std::endl;
}
The advantage of this solution is that, once opaque_delete is defined, the required boilerplate code is rather small.
I'm using the pimpl-idiom with std::unique_ptr:
class window {
window(const rectangle& rect);
private:
class window_impl; // defined elsewhere
std::unique_ptr<window_impl> impl_; // won't compile
};
However, I get a compile error regarding the use of an incomplete type, on line 304 in <memory>:
Invalid application of 'sizeof' to an incomplete type 'uixx::window::window_impl'
For as far as I know, std::unique_ptr should be able to be used with an incomplete type. Is this a bug in libc++ or am I doing something wrong here?
Here are some examples of std::unique_ptr with incomplete types. The problem lies in destruction.
If you use pimpl with unique_ptr, you need to declare a destructor:
class foo
{
class impl;
std::unique_ptr<impl> impl_;
public:
foo(); // You may need a def. constructor to be defined elsewhere
~foo(); // Implement (with {}, or with = default;) where impl is complete
};
because otherwise the compiler generates a default one, and it needs a complete declaration of foo::impl for this.
If you have template constructors, then you're screwed, even if you don't construct the impl_ member:
template <typename T>
foo::foo(T bar)
{
// Here the compiler needs to know how to
// destroy impl_ in case an exception is
// thrown !
}
At namespace scope, using unique_ptr will not work either:
class impl;
std::unique_ptr<impl> impl_;
since the compiler must know here how to destroy this static duration object. A workaround is:
class impl;
struct ptr_impl : std::unique_ptr<impl>
{
~ptr_impl(); // Implement (empty body) elsewhere
} impl_;
As Alexandre C. mentioned, the problem comes down to window's destructor being implicitly defined in places where the type of window_impl is still incomplete. In addition to his solutions, another workaround that I've used is to declare a Deleter functor in the header:
// Foo.h
class FooImpl;
struct FooImplDeleter
{
void operator()(FooImpl *p);
};
class Foo
{
...
private:
std::unique_ptr<FooImpl, FooImplDeleter> impl_;
};
// Foo.cpp
...
void FooImplDeleter::operator()(FooImpl *p)
{
delete p;
}
Note that using a custom Deleter function precludes the use of std::make_unique (available from C++14), as already discussed here.
use a custom deleter
The problem is that unique_ptr<T> must call the destructor T::~T() in its own destructor, its move assignment operator, and unique_ptr::reset() member function (only). However, these must be called (implicitly or explicitly) in several PIMPL situations (already in the outer class's destructor and move assignment operator).
As already pointed out in another answer, one way to avoid that is to move all operations that require unique_ptr::~unique_ptr(), unique_ptr::operator=(unique_ptr&&), and unique_ptr::reset() into the source file where the pimpl helper class is actually defined.
However, this is rather inconvenient and defies the very point of the pimpl idoim to some degree. A much cleaner solution that avoids all that is to use a custom deleter and only move its definition into the source file where the pimple helper class lives. Here is a simple example:
// file.h
class foo
{
struct pimpl;
struct pimpl_deleter { void operator()(pimpl*) const; };
std::unique_ptr<pimpl,pimpl_deleter> m_pimpl;
public:
foo(some data);
foo(foo&&) = default; // no need to define this in file.cc
foo&operator=(foo&&) = default; // no need to define this in file.cc
//foo::~foo() auto-generated: no need to define this in file.cc
};
// file.cc
struct foo::pimpl
{
// lots of complicated code
};
void foo::pimpl_deleter::operator()(foo::pimpl*ptr) const { delete ptr; }
Instead of a separate deleter class, you can also use a free function or static member of foo:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
using deleter = void(&)(pimpl*);
std::unique_ptr<pimpl,deleter> m_pimpl;
public:
foo(some data);
};
Probably you have some function bodies within .h file within class that uses incomplete type.
Make sure that within your .h for class window you have only function declaration. All function bodies for window must be in .cpp file. And for window_impl as well...
Btw, you have to explicitly add destructor declaration for windows class in your .h file.
But you CANNOT put empty dtor body in you header file:
class window {
virtual ~window() {};
}
Must be just a declaration:
class window {
virtual ~window();
}
To add to the other's replies about the custom deleter, in our internal "utilities library" I added a helper header to implement this common pattern (std::unique_ptr of an incomplete type, known only to some of the TU to e.g. avoid long compile times or to provide just an opaque handle to clients).
It provides the common scaffolding for this pattern: a custom deleter class that invokes an externally-defined deleter function, a type alias for a unique_ptr with this deleter class, and a macro to declare the deleter function in a TU that has a complete definition of the type. I think that this has some general usefulness, so here it is:
#ifndef CZU_UNIQUE_OPAQUE_HPP
#define CZU_UNIQUE_OPAQUE_HPP
#include <memory>
/**
Helper to define a `std::unique_ptr` that works just with a forward
declaration
The "regular" `std::unique_ptr<T>` requires the full definition of `T` to be
available, as it has to emit calls to `delete` in every TU that may use it.
A workaround to this problem is to have a `std::unique_ptr` with a custom
deleter, which is defined in a TU that knows the full definition of `T`.
This header standardizes and generalizes this trick. The usage is quite
simple:
- everywhere you would have used `std::unique_ptr<T>`, use
`czu::unique_opaque<T>`; it will work just fine with `T` being a forward
declaration;
- in a TU that knows the full definition of `T`, at top level invoke the
macro `CZU_DEFINE_OPAQUE_DELETER`; it will define the custom deleter used
by `czu::unique_opaque<T>`
*/
namespace czu {
template<typename T>
struct opaque_deleter {
void operator()(T *it) {
void opaque_deleter_hook(T *);
opaque_deleter_hook(it);
}
};
template<typename T>
using unique_opaque = std::unique_ptr<T, opaque_deleter<T>>;
}
/// Call at top level in a C++ file to enable type %T to be used in an %unique_opaque<T>
#define CZU_DEFINE_OPAQUE_DELETER(T) namespace czu { void opaque_deleter_hook(T *it) { delete it; } }
#endif
May be not a best solution, but sometimes you may use shared_ptr instead.
If course it's a bit an overkill, but... as for unique_ptr, I'll perhaps wait 10 years more until C++ standard makers will decide to use lambda as a deleter.
Another side.
Per your code it may happen, that on destruction stage window_impl will be incomplete. This could be a reason of undefined behaviour.
See this:
Why, really, deleting an incomplete type is undefined behaviour?
So, if possible I would define a very base object to all your objects, with virtual destructor. And you're almost good. You just should keep in mind that system will call virtual destructor for your pointer, so you should define it for every ancestor. You should also define base class in inheritance section as a virtual (see this for details).
Using extern template
The issue with using std::unique_ptr<T> where T is an incomplete type is that unique_ptr needs to be able to delete an instance of T for various operations. The class unique_ptr uses std::default_delete<T> to delete the instance. Hence, in an ideal world, we would just write
extern template class std::default_delete<T>;
to prevent std::default_delete<T> from being instantiated. Then, declaring
template class std::default_delete<T>;
at a place where T is complete, would instantiate the template.
The issue here is that default_delete actually defines inline methods that will not be instantiated. So, this idea does not work. We can, however, work around this problem.
First, let us define a deleter that does not inline the call operator.
/* --- opaque_ptr.hpp ------------------------------------------------------- */
#ifndef OPAQUE_PTR_HPP_
#define OPAQUE_PTR_HPP_
#include <memory>
template <typename T>
class opaque_delete {
public:
void operator() (T* ptr);
};
// Do not move this method into opaque_delete, or it will be inlined!
template <typename T>
void opaque_delete<T>::operator() (T* ptr) {
std::default_delete<T>()(ptr);
}
Furthermore, for ease of use, define a type opaque_ptr which combines unique_ptr with opaque_delete, and analogously to std::make_unique, we define make_opaque.
/* --- opaque_ptr.hpp cont. ------------------------------------------------- */
template <typename T>
using opaque_ptr = std::unique_ptr<T, opaque_delete<T>>;
template<typename T, typename... Args>
inline opaque_ptr<T> make_opaque(Args&&... args)
{
return opaque_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
The type opaque_delete can now be used with the extern template construction. Here is an example.
/* --- foo.hpp -------------------------------------------------------------- */
#ifndef FOO_HPP_
#define FOO_HPP_
#include "opaque_ptr.hpp"
class Foo {
public:
Foo(int n);
void print();
private:
struct Impl;
opaque_ptr<Impl> m_ptr;
};
// Do not instantiate opaque_delete.
extern template class opaque_delete<Foo::Impl>;
#endif
Since we prevent opaque_delete from being instantiated this code compiles without errors. To make the linker happy, we instantiate opaque_delete in our foo.cpp.
/* --- foo.cpp -------------------------------------------------------------- */
#include "foo.hpp"
#include <iostream>
struct Foo::Impl {
int n;
};
// Force instantiation of opaque_delete.
template class opaque_delete<Foo::Impl>;
The remaining methods could be implemented as follows.
/* --- foo.cpp cont. -------------------------------------------------------- */
Foo::Foo(int n)
: m_ptr(new Impl)
{
m_ptr->n = n;
}
void Foo::print() {
std::cout << "n = " << m_ptr->n << std::endl;
}
The advantage of this solution is that, once opaque_delete is defined, the required boilerplate code is rather small.
This is a very noobish mistake, but I dont know whats happening here.
There are loads of pimpl examples but I dont understand why this isn't working (this was one of the examples more or less but I dont see the difference).
I have a very simple Pimpl example, but it wont work.
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
//boost::scoped_ptr<Bar> pImpl;
Bar* pImpl;
public:
Foo();
~Foo() {}
int returnValue();
private:
};
and
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
Bar() {}
~Bar() {}
int value;
};
Foo::Foo() : pImpl(new Bar())
{
pImpl->value = 7;
}
int Foo::returnValue() {
return *pImpl->value;
}
Compiling this gives me the error.
C2100: illegal indirection.
Thanks.
int returnValue() should be a member function:
// vvvvv
int Foo::returnValue() {
return pImpl->value; // no need to dereference, value isn't a pointer
}
You need to define your constructor, copy-constructor, copy assignment operator, and destructor after the implementation class has been defined. (Otherwise the implicit destructor is dangerous, and scoped_ptr won't let you do that):
// Foo.hpp
#include <boost/scoped_ptr.hpp>
class Foo
{
struct Bar;
boost::scoped_ptr<Bar> pImpl;
public:
Foo();
~Foo();
int returnValue(); // could be const (so should be)
private:
// just disable copying, like scoped_ptr
Foo(const Foo&); // not defined
Foo& operator=(const Foo&); // not defined
};
And:
// Foo.cpp
#include "foo.hpp"
struct Foo::Bar
{
int value;
};
Foo::Foo() :
pImpl(new Bar())
{
pImpl->value = 7;
}
Foo::~Foo()
{
// okay, Bar defined at this point; scoped_ptr can work
}
int Foo::returnValue()
{
return pImpl->value;
}
As an aside, you may have a problem using boost::scoped_ptr for a pImpl because your pImpl is forwardly declared and you may find that the class needs to be fully visible in order to call scoped_ptr's destructor (which deletes the underlying).
Some compilers will allow you to work around this by putting the body of your destructor in the compilation unit (the .cpp file) where the class is visible.
The simplest solution is that if your destructor has to be implemented anyway you may as well just use a raw pointer and have your destructor delete it. And if you want to use something from boost to help you, derive your outer class from boost::noncopyable. Otherwise ensure you handle copy-construction and assignment properly.
You can use shared_ptr to your pImpl. You can then copy your outer class around happily although they share the same underlying unless you overload the copy-constructor and assignment operator to do otherwise.