Ну, как работает пользовательский делетер std:: unique ptr?
согласно N3290 std::unique_ptr
принимает аргумент deleter в своем конструкторе.
однако я не могу заставить это работать с Visual C++ 10.0 или MinGW g++ 4.4.1 в Windows, а также с g++ 4.6.1 в Ubuntu.
предпочтительно я хотел бы также посмотреть, как это работает unique_ptr<Base> p = unique_ptr<Derived>( new Derived )
.
возможно, с некоторой формулировкой из стандарта для резервного копирования примера, т. е. что с любым компилятором, который вы используете, он на самом деле делает то, что он должен делать?
4 ответа:
это работает для меня в MSVC10
int x = 5; auto del = [](int * p) { std::cout << "Deleting x, value is : " << *p; }; std::unique_ptr<int, decltype(del)> px(&x, del);
и на gcc 4.5,здесь
Я пропущу переход к стандарту, если вы не думаете, что этот пример делает именно то, что вы ожидаете от него.
чтобы дополнить все предыдущие ответы, есть способ иметь пользовательский удалитель без необходимости "загрязнять" подпись unique_ptr, имея либо указатель функции, либо что-то эквивалентное в нем:
std::unique_ptr< MyType, myTypeDeleter > // not pretty
это достижимо путем предоставления специализации классу шаблонов std:: default_delete, например:
namespace std { template<> class default_delete< MyType > { public: void operator()(MyType *ptr) { delete ptr; } }; }
и теперь все
std::unique_ptr< MyType >
что "видит" эта специализация будет удалена с него. Просто знайте, что это может быть не то, что вы хочу для всехstd::unique_ptr< MyType >
, поэтому тщательно выбрал ваше решение.
на мой вопрос уже довольно хорошо ответили.
но на всякий случай люди задавались вопросом, у меня было ошибочное мнение, что a
unique_ptr<Derived>
может быть перемещен вunique_ptr<Base>
и тогда вспомнил бы делетер дляDerived
объект, то есть, чтоBase
не нужно было бы иметь виртуальный деструктор. Это было неправильно. Я бы выбрал комментарий Керрека СБ как "ответ", за исключением того, что нельзя сделать это для комментария.@Howard: ниже код иллюстрирует один из способов достижения того, что я считал стоимость динамически назначенного делетера должна была означать, что
unique_ptr
поддержка:#include <iostream> #include <memory> // std::unique_ptr #include <functional> // function #include <utility> // move #include <string> using namespace std; class Base { public: Base() { cout << "Base:<init>" << endl; } ~Base() { cout << "Base::<destroy>" << endl; } virtual string message() const { return "Message from Base!"; } }; class Derived : public Base { public: Derived() { cout << "Derived::<init>" << endl; } ~Derived() { cout << "Derived::<destroy>" << endl; } virtual string message() const { return "Message from Derived!"; } }; class BoundDeleter { private: typedef void (*DeleteFunc)( void* p ); DeleteFunc deleteFunc_; void* pObject_; template< class Type > static void deleteFuncImpl( void* p ) { delete static_cast< Type* >( p ); } public: template< class Type > BoundDeleter( Type* pObject ) : deleteFunc_( &deleteFuncImpl< Type > ) , pObject_( pObject ) {} BoundDeleter( BoundDeleter&& other ) : deleteFunc_( move( other.deleteFunc_ ) ) , pObject_( move( other.pObject_ ) ) {} void operator() (void*) const { deleteFunc_( pObject_ ); } }; template< class Type > class SafeCleanupUniquePtr : protected unique_ptr< Type, BoundDeleter > { public: typedef unique_ptr< Type, BoundDeleter > Base; using Base::operator->; using Base::operator*; template< class ActualType > SafeCleanupUniquePtr( ActualType* p ) : Base( p, BoundDeleter( p ) ) {} template< class Other > SafeCleanupUniquePtr( SafeCleanupUniquePtr< Other >&& other ) : Base( move( other ) ) {} }; int main() { SafeCleanupUniquePtr< Base > p( new Derived ); cout << p->message() << endl; }
спасибо,
это работает. Разрушение происходит правильно.
class Base { public: Base() { std::cout << "Base::Base\n"; } virtual ~Base() { std::cout << "Base::~Base\n"; } }; class Derived : public Base { public: Derived() { std::cout << "Derived::Derived\n"; } virtual ~Derived() { std::cout << "Derived::~Derived\n"; } }; void Delete(const Base* bp) { delete bp; } int main() { std::unique_ptr<Base, void(*)(const Base*)> ptr = std::unique_ptr<Derived, void(*)(const Base*)>(new Derived(), Delete); }