excuse me, when I was implementing pimpl with std::unique_ptr, I accidentally found that when I set pimpl to nullptr in the header file, gcc(version 9.4.0,14.1.0) cannot be compiled. But cl.exe (version 19.20.27508.1) can be compiled, cancel the assignment, then can be compiled, I tried to find the possibility, but finally did not have an answer
The code is as follows:
// main.cpp
#include <iostream>
#include <memory>
#include "feature.hpp"
int main() {
auto wrap = std::make_shared<Wrap>();
wrap->print666();
}
// feature.hpp
#include <memory>
class Wrap {
private:
class Impl;
std::unique_ptr<Impl> pimpl
= nullptr // This line assignment is key
;
public:
Wrap();
~Wrap();
void print666() const;
void print888() const;
};
// feature.cpp
#include "feature.hpp"
#include <iostream>
class Wrap::Impl {
public:
void print666() const {
std::cout << "666" << std::endl;
}
void print888() const {
std::cout << "888" << std::endl;
}
};
void Wrap::print666() const {
pimpl->print666();
}
void Wrap::print888() const {
pimpl->print888();
}
Wrap::Wrap(): pimpl(new Impl){}
Wrap::~Wrap() = default;
The compile command is as follows:
# on linux
g++ -g -O0 -std=c++17 main.cpp feature.cpp -o main.out
# or on Windows
cl /EHsc /Femain.exe /std:c++17 main.cpp feature.cpp
(gcc9.4.0) When there is an assignment, the error message is as follows:
In file included from /usr/include/c++/9/memory:80,
from main.cpp:2:
/usr/include/c++/9/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Wrap::Impl]’:
/usr/include/c++/9/bits/unique_ptr.h:292:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Wrap::Impl; _Dp = std::default_delete<Wrap::Impl>]’
feature.hpp:7:11: required from here
/usr/include/c++/9/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘Wrap::Impl’
79 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
I understand that the common reason for the above problems is that the deleter of std::unique_ptr needs to know the complete type of the Impl object, so it needs to implement the Wrap constructor and destructor after the Impl class definition appears. But I don’t understand why assigning std::unique_ptr in the Wrap class declaration also causes this problem, because std::unique_ptr should not actually be initialized at this point, this initialization should be delayed to the Wrap constructor while the Impl is complete, so I think the msvc compiler is the expected behavior. Expect the correct explanation, thanks.
Bart Simpson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.