Make std :: unique <T> compatible with std :: unique <const T, CustomDeleterType>
In the code, I have 3 types of std :: unique_ptr defined for a specific object:
typedef std::unique_ptr<MyObject> nonConstPtrDefaultDelete;
typedef std::unique_ptr<MyObject, std::function<void(MyObject *)>>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, std::function<void(const MyObject *)>>
ConstPtrCustomDelete;
I came across a use case when I need to convert nonConstPtrDefaultDelete to ConstPtrCustomDelete and nonConstPtrCustomDelete to ConstPtrCustomDelete. In other words:
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1(a); // Compiler error Deleter has incompatible type
ConstPtrCustomDelete c2(b); // Compiler error Deleter has incompatible type
The main problem is related to incompatibility of type signatures for delete functions. You can fix the case of nonConstPtrCustomDelete by changing the definition of the nonConstPtrCustomDelete type as follows:
typedef std::unique_ptr<MyObject, std::function<void(const MyObject *)>>
nonConstPtrCustomDelete
DefaultDelete , , , . , , , , ?
,
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1(a); // Compiler error Deleter has incompatible type
ConstPtrCustomDelete c2(b); // Compiler error Deleter has incompatible type
& hellip; :
unique_ptr
lvalue. , lvalue .void(T*)
void(T const*)
.
A void(T const*)
, T const*
, , T*
. , , . , ++, T const*
( ), delete p;
.
std::move
<utility>
:
ConstPtrCustomDelete c1( move( a ) );
ConstPtrCustomDelete c2( move( b ) );
, unique_ptr
, std::default_delete<T const>
.
, , , 1 const
-ness:
template< class Type >
class Deleter
{
private:
function<void(Type const*)> d_;
public:
using Mutable_type = typename remove_const<Type>::type;
void operator()( Type const* p ) const
{
d_( p );
}
Deleter(): d_( default_delete<Type const>() ) {}
Deleter( default_delete<Mutable_type> const& )
: d_( default_delete<Type const>() )
{}
template< class D >
Deleter( D const& d )
: d_( [d]( Type const* p ) {
d( const_cast<Mutable_type*>( p ) );
} )
{}
};
move
,
typedef std::unique_ptr<MyObject> nonConstPtrDefaultDelete;
typedef std::unique_ptr<MyObject, Deleter<MyObject>>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, Deleter<MyObject const>>
ConstPtrCustomDelete;
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1( move( a ) );
ConstPtrCustomDelete c2( move( b ) );
< > 1 const_cast
, UB, const
, d
- const
. , . , .
>
std::function
?
nonConstPtrCustomDelete
, , , ?
. - :
void foo_deleter(MyObject*);
void bar_deleter(MyObject*);
nonConstPtrCustomDelete ptr1{ foo(), foo_deleter };
nonConstPtrCustomDelete ptr1{ bar(), bar_deleter };
:
nonConstPtrCustomDelete ptr1{ foo(), foo_deleter };
nonConstPtrCustomDelete ptr1{ bar(), foo_deleter };
, std::function
, . , .
:
struct non_const_deleter {
void operator()(MyObject*) const;
};
typedef :
typedef std::unique_ptr<MyObject, non_const_deleter>
nonConstPtrCustomDelete;
, :
nonConstPtrCustomDelete ptr1{ foo() };
:
nonConstPtrCustomDelete ptr1{ foo(), non_const_deleter{} };
, non_const_deleter
:
struct const_deleter {
const_deleter() = default;
const_deleter(const non_const_deleter&) { }
void operator()(const MyObject*) const;
};
, , :
struct const_and_non_const_deleter {
void operator()(MyObject*) const;
void operator()(const MyObject*) const;
};
Then both types can use the same debiter:
typedef std::unique_ptr<MyObject, const_and_non_const_deleter>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, const_and_non_const_deleter>
constPtrCustomDelete;
and you will not have problems converting nonConstPtr to constPtr.