问题
According to N3290 std::unique_ptr
accepts a deleter argument in its constructor.
However, I can\'t get that to work with Visual C++ 10.0 or MinGW g++ 4.4.1 in Windows, nor with g++ 4.6.1 in Ubuntu.
I therefore fear that my understanding of it is incomplete or wrong, I can\'t see the point of a deleter argument that\'s apparently ignored, so can anyone provide a working example?
Preferably I\'d like to see also how that works for unique_ptr<Base> p = unique_ptr<Derived>( new Derived )
.
Possibly with some wording from the standard to back up the example, i.e. that with whatever compiler you\'re using, it actually does what it\'s supposed to do?
回答1:
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.
回答2:
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.
回答3:
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;
}
Cheers,
回答4:
This works. The destruction happens properly.
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);
}
来源:https://stackoverflow.com/questions/8274451/well-how-does-the-custom-deleter-of-stdunique-ptr-work