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 , , , . , , , , ?

+4
4

, deleter , DefaultDelete :

nonConstPtrDefaultDelete a;
ConstPtrCustomDelete c1( a.release(), your_deleter );

const/non const. ( 1 ) .

+6

,

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 . , . , . >

+4

:

template<class T>
using smarter_default_delete = std::default_delete<const T>;

template<class T, class D=smarter_default_delete<T>>
using my_unique_ptr = std::unique_ptr<T, D>;

typedef my_unique_ptr<MyObject> nonConstPtrDefaultDelete;

, default_delete T const* s. .

, . .

+3

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.

+1
source

Source: https://habr.com/ru/post/1610589/


All Articles