Ну, как работает пользовательское деблокирование std:: unique_ptr?
В соответствии с N3290 std::unique_ptr
принимает аргумент deleter в своем конструкторе.
Однако я не могу получить это для работы с Visual С++ 10.0 или MinGW g++ 4.4.1 в Windows, а также с g++ 4.6.1 в Ubuntu.
Поэтому я опасаюсь, что мое понимание этого является неполным или неправильным, я не вижу смысла аргумента, который, по-видимому, игнорируется, может ли кто-нибудь представить рабочий пример?
Желательно также посмотреть, как это работает для unique_ptr<Base> p = unique_ptr<Derived>( new Derived )
.
Возможно, с некоторыми формулировками из стандарта для резервного копирования примера, то есть с каким-либо компилятором, который вы используете, он фактически выполняет то, что он должен делать?
Ответы
Ответ 1
Это работает для меня в 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, здесь
Я перейду к стандарту, если вы не думаете, что этот пример делает именно то, что вы ожидаете от него.
Ответ 2
Чтобы дополнить все предыдущие ответы, есть способ иметь пользовательский удаленный доступ, не "загрязнять" подпись 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 >
, поэтому тщательно выберите свое решение.
Ответ 3
Мой вопрос уже довольно хорошо ответил.
Но на всякий случай люди задавались вопросом, у меня было ошибочное убеждение, что unique_ptr<Derived>
можно перенести в unique_ptr<Base>
, а затем вспомнить делетера для объекта Derived
, т.е. что Base
не понадобится иметь виртуальный деструктор. Это было неправильно. Я бы выбрал комментарий Kerrek SB как "ответ", за исключением того, что не могу сделать это для комментария.
@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;
}
Приветствия,
Ответ 4
Это работает. Разрушение происходит должным образом.
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);
}