std::unique_ptr
与自定义删除器
的行为基于删除器的静态类型 .没有多态性,没有基于运行时传递的实际删除器的运行时行为,因为提供的派生删除器被切片为声明的删除器的静态类型。
(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).
带有自定义删除器
的unique_ptr
的静态行为:
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);
}
输出:
in BaseDeleter
in BaseDeleter
这与 std::shared_ptr
不同,后者以不同方式持有其自定义删除器并允许动态行为:
shared_ptr
与自定义删除器
的动态行为:
int main() {
auto shared_var = std::shared_ptr<A>(new A, BaseDeleter{});
shared_var = std::shared_ptr<A>(new A, DerivedDeleter{});
}
输出:
in BaseDeleter
in DerivedDeleter
代码:https://coliru.stacked-crooked.com/a/54a8d2fc3c95d4c1
为std::unique_ptr
分配不同的自定义删除器
的行为实际上是切片。
为什么 unique_ptr 不能阻止自定义删除器的切片?
如果分配的 unique_ptr 具有不同的 custom deleter
,为什么语言不阻止 std::unique_ptr
的分配以避免切片?
这似乎是可能的,如下所示。
阻止unique_ptr
切片自定义删除器
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;
};
最佳答案
struct B {
virtual ~B() = default;
};
struct D : B {};
std::unique_ptr<B> b;
b = std::make_unique<D>();
这里有一个经典用例。是的,删除器被切片了,但是删除仍然是明确定义的。你的提议会干扰它。并且可能很难可靠地修改为不干扰。
总是可以指定自定义删除器,如 std::function<void(void*)>
通过类型删除获得多态性。当然,它有开销,但这是选择加入。
默认 unique_ptr
针对更常见的用例进行了优化,而不太常见的需要开销的用例可以根据请求进行优化。
关于c++ - 为什么 unique_ptr 不阻止自定义删除器的切片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56308336/