简体   繁体   English

C++ 入门第 5 版:shared_ptr 和 unique_ptr 的删除器之间的区别

[英]C++ primer 5th edition: Difference between the deleter of a shared_ptr and of unique_ptr's

In "C++ Primer, 5th Edition", it is said that the type of the deleter of a shared_ptr is not known until runtime, because the deleter is not stored directly as a member, but as a pointer that can point to a deleter.在《C++ Primer, 5th Edition》中,说shared_ptr的删除器的类型直到运行时才知道,因为删除器不是直接作为成员存储的,而是作为可以指向删除器的指针存储的。 The type of the deleter in a unique_ptr is known at compile-time, because it is a part of the unique_ptr itself. unique_ptr删除器的类型在编译时是已知的,因为它是unique_ptr本身的一部分。

So, I've made this example:所以,我做了这个例子:

#include <functional>

template <typename T>
struct SharedPtr
{
    void(*pDel_)(T*) = nullptr;
    T* ptr_{ new T{} };
    ~SharedPtr(){ pDel_ ? pDel_(ptr_) : delete ptr_; }
};

template <typename T, typename D = std::function<void(T*)>>
struct UniquePtr
{
    D pDel_;
    T* ptr_{ nullptr };
    UniquePtr(T* p = nullptr, D del = D{}) :
        ptr_(p), pDel_(del){}
    ~UniquePtr(){ pDel_(ptr_); }
};

int main()
{
    SharedPtr<int> spi{};
    cout << *spi.ptr_ << endl;
    UniquePtr<std::string> upd{new std::string("Helo!"),
        [](std::string* p){std::cout << "freeing memory...\n"; delete p; }};

}
  • in my opinion, the type of the deleter in SharedPtr is known at compile time ( void(*)(T*) ) but the value is not.在我看来, SharedPtr删除器的类型在编译时是已知的( void(*)(T*) ),但值不是。

  • on the other hand, the type of the deleter in UniquePtr is really known at compile time too, but again the value may not be.另一方面, UniquePtr删除器的类型在编译时也确实是已知的,但值也可能不是。

  • So the book said that:所以书上说:

// del bound at compile time; direct call to the deleter is instantiated
del(p);   // no run-time overhead
The type of del is either the default deleter type or a user-supplied type. It doesn’t
matter; either way the code that will be executed is known at compile time. Indeed, if
the deleter is something like our DebugDelete class (§ 16.1.4, p. 672) this call might
even be inlined at compile time.
By binding the deleter at compile time, unique_ptr avoids the run-time cost of an
indirect call to its deleter. By binding the deleter at run time, shared_ptr makes it
easier for users to override the deleter.

If the deleter in UniquePtr is a pointer to a function, but that pointer is nullptr , then del(p) is undefined.如果UniquePtr的删除UniquePtr是指向函数的指针,但该指针是nullptr ,则del(p)未定义。

Please help me to understand this paragraph.请帮助我理解这一段。 I've implemented my shared_ptr and unique_ptr as a matter of practice only.我已经实现了我的shared_ptrunique_ptr作为实践问题。

in my opinion, the type of the deleter in SharedPtr is known at compile time ( void(*)(T*) ) but the value is not.在我看来, SharedPtr 中删除器的类型在编译时是已知的( void(*)(T*) ),但值不是。

That is true of your SharedPtr.您的 SharedPtr 也是如此。

That is not true of std::shared_ptr. std::shared_ptr 并非如此。

on the other hand, the type of the deleter in UniquePtr is really known at compile time too, but again the value may not be.另一方面,UniquePtr 中删除器的类型在编译时也确实是已知的,但值也可能不是。

When you instantiate UniquePtr with std::function<void(T*)> , you would only know that type at compile time, but not the type of the function object that is wrapped by it.当您使用std::function<void(T*)>实例化 UniquePtr 时,您只会在编译时知道该类型,而不知道由它包装的函数对象的类型。

std::unique_ptr does not use std::function deleter by default. std::unique_ptr 默认不使用 std::function 删除器。

If the deleter in UniquePtr is a pointer to a function, but that pointer is nullptr, then del(p) is undefined.如果 UniquePtr 中的删除器是指向函数的指针,但该指针为 nullptr,则 del(p) 未定义。

This is true.这是真的。 Don't do that.不要那样做。

Please help me to understand this paragraph.请帮助我理解这一段。

Just because a unique pointer can have a deleter known at compile time, doesn't mean that it has to have such deleter.仅仅因为一个唯一的指针在编译时可以有一个已知的删除器,并不意味着它必须有这样的删除器。 A function wrapper is not nor is function pointer a compile-time deleter because they have runtime state.函数包装器既不是函数指针,也不是编译时删除器,因为它们具有运行时状态。

Use a stateless deleter like for example std::default_delete<T> (or perhaps DebugDelete mentioned in the quote which presumably is also stateless) to get compile time benefits.使用无状态删除器,例如std::default_delete<T> (或者可能是引用中提到的 DebugDelete ,它可能也是无状态的)来获得编译时间优势。

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

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