How does the custom deleter of std::unique_ptr work?
This works for me in MSVC10
int x = 5;
auto del = [](int * p) { std::cout << "Deleting x, value is : " << *p; };
std::unique_ptr<int, decltype(del)> px(&x, del);
And on gcc 4.5, here
I'll skip going to the standard, unless you don't think that example is doing exactly what you'd expect it to do.
To complement all previous answers, there is a way to have a custom deleter without having to "pollute" the unique_ptr signature by having either a function pointer or something equivalent in it like this:
std::unique_ptr< MyType, myTypeDeleter > // not pretty
This is achievable by providing a specialization to the std::default_delete template class, like this:
namespace std
{
template<>
class default_delete< MyType >
{
public:
void operator()(MyType *ptr)
{
delete ptr;
}
};
}
And now all std::unique_ptr< MyType >
that "sees" this specialization will be deleted with it. Just be aware that it might not be what you want for all std::unique_ptr< MyType >
, so chose carefully your solution.
My question has been pretty well answered already.
But just in case people wondered, I had the mistaken belief that a unique_ptr<Derived>
could be moved to a unique_ptr<Base>
and would then remember the deleter for the Derived
object, i.e., that Base
would not need to have a virtual destructor. That was wrong. I'd select Kerrek SB's comment as "the answer", except one cannot do that for a comment.
@Howard: the code below illustrates one way to achieve what I believed the cost of a dynamically assigned deleter had to mean that unique_ptr
supported out of the box:
#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;
}