Pimpl и умные указатели
Порой понимаешь, что не знаешь каких-то банальных вещей. Сегодня на повестке дня 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() {}
Disclaimer