The behavior of std::unique_ptr
with custom deleter
is based on the static type of the deleter. No polymorphism, no runtime behavior based on actual deleter passed in runtime, as derived deleter provided is being sliced to the static type of the declared deleter.
(It is designed this way in purpose, to allow the size of unique_ptr with
default deleter
or withcustom deleter without any data members
, to have same size as a raw pointer).
static behavior of unique_ptr
with custom deleter
:
class A {};
struct BaseDeleter {
virtual void operator()(A* p) const {
std::cout << "in BaseDeleter" << std::endl;
delete p;
}
};
struct DerivedDeleter: BaseDeleter {
void operator()(A* p) const override {
std::cout << "in DerivedDeleter" << std::endl;
delete p;
}
};
int main() {
auto unique_var = std::unique_ptr<A, BaseDeleter>(new A);
unique_var = std::unique_ptr<A, DerivedDeleter>(new A);
}
Output:
in BaseDeleter
in BaseDeleter
This is opposed to std::shared_ptr
who holds its custom deleter differently and allowing dynamic behavior:
dynamic behavior of shared_ptr
with custom deleter
:
int main() {
auto shared_var = std::shared_ptr<A>(new A, BaseDeleter{});
shared_var = std::shared_ptr<A>(new A, DerivedDeleter{});
}
Output:
in BaseDeleter
in DerivedDeleter
Code: https://coliru.stacked-crooked.com/a/54a8d2fc3c95d4c1
The behavior of assigning std::unique_ptr
with different custom deleter
is actually slicing.
Why unique_ptr doesn't prevent slicing of custom deleter?
Why didn't the language block the assignment of std::unique_ptr
if the assigned unique_ptr has different custom deleter
, to avoid slicing?
This seems to be possible as presented below.
Blocking unique_ptr
from slicing of custom deleter
template<typename TYPE, typename Deleter>
struct my_unique_ptr : std::unique_ptr<TYPE, Deleter> {
using BASE = std::unique_ptr<TYPE, Deleter>;
using std::unique_ptr<TYPE, Deleter>::unique_ptr;
auto& operator=(std::nullptr_t) noexcept {
return BASE::operator=(nullptr);
}
template<typename T, typename OtherDeleter,
std::enable_if_t<!std::is_same<OtherDeleter, Deleter>::value>* dummy = nullptr>
auto& operator=(std::unique_ptr<T, OtherDeleter>&& other) = delete;
};