Reputation: 1010
There is an array holding unique pointers:
std::array<std::unique_ptr<T, deleter<allocator<T>>>> storage;
where
template<typename ALLOC>
class deleter {
void operator()( void ) { ... }
};
does the deletion as required by unique_ptr. Effectively, it calls the destructor and then deallocates the memory occupied. So far so good.
But there is another deleter:
template<typename T>
class empty_deleter {
void operator()( void ) {}
};
which performs no operation at all - no destruction, no deallocation.
The reason why it exists is to have, in theory, the option to store object owned by such unique_ptr<T, empty_deleter<T>>
within the storage array...
The question is - how to achieve that? To make the deleters compatible so that I can assign unique_ptr<T, empty_deleter<T>>
to an array of unique_ptr<T, deleter<allocator<T>>>
pointers...
I know there are converting constructors within the unique_ptr
implementation so in theory, the deleter of one type can be assinged to the unique_ptr
being declared with another type but there is a constraint these deleters shall be convertible somehow... could you please advice me how to reach that?
Additionally - once I am successfull in assigning the deleter instance of empty_deleter<T>
into unique_ptr<T, deleter<allocator<T>>>
whatever how, which operator()
is going to be called once the deletion is triggered? The one from empty_deleter<T>
or from deleter<allocator<T>>
?
Upvotes: 0
Views: 238
Reputation: 62636
As @Nicol Bolas points out, "object owned by such unique_ptr<T, empty_deleter<T>>
" is nonsensical. I will answer "how to make a smart pointer that sometimes owns and sometimes doesn't own it's pointee".
None of std::unique_ptr<T, empty_deleter<T>>
, std::unique_ptr<T, deleter<allocator<T>>>
, nor std::unique_ptr<T, deleter<other_allocator<T>>>
are assignable to one another.
If you want to mix and match ownerships of your pointers, you will have to type-erase the deleter. The simplest way is to use the existing function-object type-erasure type, std::function
.
template <typename T>
class pmr_unique_ptr : public std::unique_ptr<T, std::function<void(T *)>> {
public:
using unique_ptr::unique_ptr;
// have to supply a deleter
pmr_unique_ptr(pointer) = delete;
pmr_unique_ptr() = delete;
pmr_unique_ptr(std::nullptr_t) = delete;
};
This can be constructed from std::unique_ptr<T, D>
so long as D
is copyable.
Upvotes: 0
Reputation: 473272
You can do this by simply release
ing the pointer from one object and passing it to the other. These two types are incompatible by design. You are not supposed to make them compatible, so you have to do this weird thing to make it work.
Yes, you could make this work by making deleter
constructible and assignable from an empty_deleter
. But that is bad, because it logically makes no sense.
unique_ptr
is supposed to own the object; that's what it is for. You shouldn't want to have a non-owning unique_ptr
. If someone gets a unique_ptr
, that's supposed to mean they own that thing.
Worse, the very idea of taking a non-owning pointer and claiming ownership of it is highly dubious. If a piece of code does not have the right to delete something (which is what the type unique_ptr<T, empty_deleter<T>>
is supposed to mean), it also does not have the right to delegate responsibility for deleting it to someone else.
The code you are trying to write is highly unclear on who owns what (or even what it means to "own" an object) and should be rethought.
Upvotes: 4