繁体   English   中英

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

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

具有custom deleterstd::unique_ptr的行为基于custom deleter器的静态类型 没有多态性,没有基于在运行时传递的实际删除器的运行时行为,因为提供的派生删除器被切片到声明的删除器的静态类型。

(它以这种方式设计,允许使用default deleter的unique_ptr的大小或custom deleter without any data members大小,以使其具有与原始指针相同的大小)。

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);
}

输出:

in BaseDeleter
in BaseDeleter

这与std::shared_ptr相反,后者以不同方式保存自定义删除器并允许动态行为:

shared_ptrcustom deleter动态行为:

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


使用不同的custom deleter分配std::unique_ptr的行为实际上是切片

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

如果指定的unique_ptr具有不同的custom deleter ,为什么语言不会阻止std::unique_ptr的赋值,以避免切片?


这似乎是可能的,如下所示。

阻止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;
};

代码: 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针对更常见的用例进行了优化,不常见的用例需要通过请求进行开销。

暂无
暂无

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

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