c++ - 为什么 unique_ptr 不阻止自定义删除器的切片?

标签 c++ unique-ptr object-slicing

std::unique_ptr自定义删除器 的行为基于删除器的静态类型 .没有多态性,没有基于运行时传递的实际删除器的运行时行为,因为提供的派生删除器被切片为声明的删除器的静态类型。

(It is designed this way in purpose, to allow the size of unique_ptr with default deleter or with custom 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;
};

代码:http://coliru.stacked-crooked.com/a/089cd4c7303ad63e

最佳答案

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/

相关文章:

c++ - C++ 中的简单代码在 Linux 中编译但不执行

c++ - AVL树的中序遍历,将值保存在数组中

c++ - 如何操作包含 `unique_ptr` 的类的实例?

c++ - Vector 内的类切片

c++ - 从继承的异常类抛出字符串异常

c++ - 为什么要在 C++ 中初始化静态类变量?

c++ - vector::erase 是否会对 vector 中的元素重新排序?

c++ - 为什么 "const"没有导致编译错误

c++ - 对 unique_ptrs 集的原始指针查找

c++ - 关于构造函数匹配和隐式转换的问题