Порой понимаешь, что не знаешь каких-то банальных вещей. Сегодня на повестке дня Pimpl и умные указатели. Я почему-то был уверен, что forward class declaration можно делать только если класс используется в форме указателя или ссылки (#1), то есть тексте записывается в форме T*
или T&
(#2). Поэтому, когда мне надо было реализовать Pimpl, я не использовал умные указатели, так как с виду для них требуется полное определение класса.
A.h
:
#include <memory> class A_pimpl; class A { … std::unique_ptr<A_pimpl> p; }
Я почему-то думал, что это не будет работать из-за неопределенности класса A_pimpl
. И был сильно удивлен, попробовал и узнав, что на самом деле это прекрасно работает. То есть факт #1 не эквивалентен факту #2.
В A.cpp
можно теперь спокойно писать:
#include "A.h" #include "pimpl.h" A::A() : p(new A_pimpl()) {}
Все выше сказанное также работает для std::shared_ptr
(C++ 2011), boost::scoped_ptr
и boost::shared_ptr
.
Дополнение
Как меня поправили в комментариях, у класса A
обязательно должен быть явно задан деструктор, причем его тело должно быть именно в A.cpp
, а не в заголовочном файле. Иначе будет ошибка типа “error C2338: can’t delete an incomplete type”.
A.h
:
#include <memory> class A_pimpl; class A { A(); ~A(); std::unique_ptr<A_pimpl> p; }
и A.cpp
:
#include "A.h" #include "pimpl.h" A::A() : p(new A_pimpl()) {} A::~A() {}