Я пытаюсь использовать boost::scoped_ptr
с моим классом реализации, который виден только в файле cpp содержащего класса. Содержащий класс имеет явно определенный деструктор (не встроенный), но мой компилятор (Borland C ++ 5.6.4) не может скомпилироваться.
Если я использую boost::shared_ptr
вместо этого тот же пример компилируется и запускается, как и ожидалось.
Что я делаю неправильно?
Редактировать: извините за то, что вы забыли показать исходный код, ошибку компилятора и (ожидаемый) вывод здесь:
файл check_shared.cpp
:
// shortened.
#include "SmartPtrTest.h"void check_shared()
{
Containing t;
}
файл SmartPtrTest.h
:
#include <boost/noncopyable.hpp>
#include <boost/smart_ptr.hpp>
class Impl;
#define smart_ptr boost::scoped_ptr
class Containing: private boost::noncopyable
{
public:
Containing();
~Containing();
private:
smart_ptr<Impl> impl;
};
файл SmartPtrTest.cpp
:
#include "SmartPtrTest.h"#include <iostream>
using namespace std;
class Impl {
public:
Impl() {
cout << "ctr Impl" << endl;
}
~Impl() {
cout << "dtr Impl" << endl;
}
};
Containing::Containing(): impl(new Impl)
{
cout << "ctr Containing" << endl;
}
Containing::~Containing()
{
cout << "dtr Containing" << endl;
}
…это что-то вроде undefined structure 'Impl'
(это немецкий: Undefinierte Struktur ‘Impl’). При компиляции файла check_shared.cpp
компилятор останавливается в файле boost/checked_delete.hpp
в typedef
этой функции:
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
Этот вывод я получаю при использовании boost::share_ptr
, показывая, что ctr и dtr вызываются, как и ожидалось.
ctr Impl
ctr Containing
dtr Containing
dtr Impl
Это должно работать до тех пор, пока класс «реализации» завершен в любой точке, в которой интеллектуальный указатель может быть уничтожен. Это происходит не только в деструкторе, но и в конструкторах — они должны уничтожить член-указатель, если они выходят из-за исключения.
Поэтому убедитесь, что ваши конструкторы и деструктор определены в исходном файле после определения класса реализации.
(Это основано на предположении, что вы получаете ошибку компиляции из-за попытки уничтожить неполный тип. Если вы получаете другую ошибку, или неожиданное поведение во время выполнения, или изменение не исправляет это, пожалуйста, обновите вопрос, чтобы продемонстрировать актуальная проблема.)
Это определенно связано с ошибкой компилятора. К сожалению, он все еще существует в C ++ Builder XE8. Смотрите эту связанную проблему здесь, и ответ от Энди Prowl: Допустимо ли для компилятора C ++ неявно создавать экземпляры ВСЕХ функций-членов шаблонного класса?
О проблеме сообщили в Embarcadero здесь: Компилятор bcc32 вызывает неопределенное поведение при использовании std :: auto_ptr с идиомой PIMPL, поскольку правила создания шаблонов не соответствуют спецификации C ++
Если вы можете использовать один из более новых компиляторов на основе clang от Embarcadero, у вас все будет в порядке. Мой тестовый пример проходит в 64-битном компиляторе clang.
ОБНОВИТЬ: Мы решили эту проблему, написав собственный класс интеллектуальных указателей, который похож на unique_ptr
в том, что он содержит checked_delete
функция, которая не реализована внутри класса. Вместо этого вы должны явно создать экземпляр checked_delete
функция внутри ОДНОЙ единицы перевода, которая также содержит реализацию частного класса. Макрос используется, чтобы помочь с этим. То есть:
template<class X> class unique_ptr_bcc32 {
// Deletes the object using operator delete:
private: static void checked_delete(X* p);
// <snip>
}
Позже, в файле CPP:
class PIMPL { /* snip implementation */ };
// You can simplify this by way of a macro:
template <> void unique_ptr_bcc32<PIMPL>::checked_delete(PIMPL* p) {
typedef char type_must_be_complete[sizeof(PIMPL) ? 1 : -1];
static_cast<void>(sizeof(type_must_be_complete));
delete p;
}
Это не оставляет места для забавного бизнеса со стороны компилятора, когда дело доходит до создания и удаления шаблона.