0

Encouraged by @xtofl in How do I use unique_ptr for pimpl? here I'd like to raise a question:

Why I cannot implement PImpl idiom using std::unique_ptr without user defined constructor?

Consider following code:

#include <memory>

class X {
public:
    // X();
    ~X();

private:
    struct Impl;
    std::unique_ptr<Impl> impl_;
};

int main() {
    X x;
}

g++ fails with following error

In file included from C:/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/memory:80,
                 from pimpl.cpp:1:
.../x86_64-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = X::Impl]':
.../x86_64-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:274:17:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = X::Impl; _Dp = std::default_delete<X::Impl>]'
pimpl.cpp:3:7:   required from here
.../x86_64-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:79:16: error: invalid application of 'sizeof' to incomplete type 'X::Impl'
  static_assert(sizeof(_Tp)>0,
                ^~~~~~~~~~~

clang fails with following error:

In file included from pimpl.cpp:1:
...\14.16.27023\include\memory:2082:21: error: invalid application of 'sizeof' to an incomplete type 'X::Impl'
                static_assert(0 < sizeof (_Ty),
                                  ^~~~~~~~~~~~
...\14.16.27023\include\memory:2296:4: note: in instantiation of member function 'std::default_delete<X::Impl>::operator()' requested here
                        this->get_deleter()(get());
                        ^
pimpl.cpp:3:7: note: in instantiation of member function 'std::unique_ptr<X::Impl, std::default_delete<X::Impl> >::~unique_ptr' requested here
class X {
      ^
pimpl.cpp:9:12: note: forward declaration of 'X::Impl'
    struct Impl;
           ^

Visual Studio fails with the following error:

pimpl.cpp
...\14.16.27023\include\memory(2082): error C2027: use of undefined type 'X::Impl'
pimpl.cpp(9): note: see declaration of 'X::Impl'
...14.16.27023\include\memory(2081): note: while compiling class template member function 'void std::default_delete<_Ty>::operator ()(_Ty *) noexcept const'
        with
        [
            _Ty=X::Impl
        ]
...\14.16.27023\include\memory(2296): note: see reference to function template instantiation 'void std::default_delete<_Ty>::operator ()(_Ty *) noexcept const' being compiled
        with
        [
            _Ty=X::Impl
        ]
...\14.16.27023\include\memory(2132): note: see reference to class template instantiation 'std::default_delete<_Ty>' being compiled
        with
        [
            _Ty=X::Impl
        ]
...\14.16.27023\include\memory(2179): note: see reference to class template instantiation 'std::_Unique_ptr_base<_Ty,_Dx>' being compiled
        with
        [
            _Ty=X::Impl,
            _Dx=std::default_delete<X::Impl>
        ]
pimpl.cpp(10): note: see reference to class template instantiation 'std::unique_ptr<X::Impl,std::default_delete<_Ty>>' being compiled
        with
        [
            _Ty=X::Impl
        ]
...\14.16.27023\include\memory(2082): error C2338: can't delete an incomplete type
...\14.16.27023\include\memory(2084): warning C4150: deletion of pointer to incomplete type 'X::Impl'; no destructor called
pimpl.cpp(9): note: see declaration of 'X::Impl'

0 Answers0