简体   繁体   English

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

[英]Why unique_ptr doesn't prevent slicing of custom deleter?

The behavior of std::unique_ptr with custom deleter is based on the static type of the deleter. 具有custom deleterstd::unique_ptr的行为基于custom 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 with custom deleter without any data members , to have same size as a raw pointer). (它以这种方式设计,允许使用default deleter的unique_ptr的大小或custom deleter without any data members大小,以使其具有与原始指针相同的大小)。

static behavior of unique_ptr with custom deleter : custom deleterunique_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);
}

Output: 输出:

in BaseDeleter
in BaseDeleter

This is opposed to std::shared_ptr who holds its custom deleter differently and allowing dynamic behavior: 这与std::shared_ptr相反,后者以不同方式保存自定义删除器并允许动态行为:

dynamic behavior of shared_ptr with custom deleter : shared_ptrcustom 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 代码: https//coliru.stacked-crooked.com/a/54a8d2fc3c95d4c1


The behavior of assigning std::unique_ptr with different custom deleter is actually slicing . 使用不同的custom deleter分配std::unique_ptr的行为实际上是切片

Why unique_ptr doesn't prevent slicing of custom deleter? 为什么unique_ptr不会阻止自定义删除器的切片?

Why didn't the language block the assignment of std::unique_ptr if the assigned unique_ptr has different custom deleter , to avoid slicing? 如果指定的unique_ptr具有不同的custom deleter ,为什么语言不会阻止std::unique_ptr的赋值,以避免切片?


This seems to be possible as presented below. 这似乎是可能的,如下所示。

Blocking unique_ptr from slicing of custom deleter 阻止unique_ptr切割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;
};

Code: http://coliru.stacked-crooked.com/a/089cd4c7303ad63e 代码: 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>();

Here we have a classic use case. 这里我们有一个经典的用例。 Yes, the deleter is sliced, but deletion is still well defined. 是的,删除器被切片,但删除仍然很明确。 Your proposal will interfere with that. 你的提议会干扰这一点。 And will probably be very hard to amend reliably into not interfering. 并且可能很难可靠地修改为不干扰。

One can always specify a custom deleter like std::function<void(void*)> to get polymorphism by type erasure. 可以随时指定一个自定义删除器,如std::function<void(void*)>以通过类型擦除获得多态性。 Sure, it has overhead, but that's opt in. 当然,它有开销,但这是选择。

By default unique_ptr is optimized for the more common use cases, with less common ones that require overhead being possible by request. 默认情况下, unique_ptr针对更常见的用例进行了优化,不常见的用例需要通过请求进行开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM