C++ 入门第 5 版:shared_ptr 和 unique_ptr 的删除器之间的区别
C++ primer 5th edition: Difference between the deleter of a shared_ptr and of unique_ptr's
在《C++ Primer, 5th Edition》中说,a shared_ptr
的删除器的类型直到运行时才知道,因为删除器不是直接存储为成员,而是作为一个可以指向删除器的指针。 unique_ptr
中删除器的类型在编译时是已知的,因为它是 unique_ptr
本身的一部分。
所以,我做了这个例子:
#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; }};
}
在我看来,SharedPtr
中删除器的类型在编译时是已知的(void(*)(T*)
),但值不是。
另一方面,UniquePtr
中删除器的类型在编译时确实也是已知的,但值可能不是。
所以书上说:
// 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.
如果 UniquePtr
中的删除器是指向函数的指针,但该指针是 nullptr
,则 del(p)
未定义。
请帮助我理解这一段。我实施 shared_ptr
和 unique_ptr
只是为了实践。
in my opinion, the type of the deleter in SharedPtr is known at compile time (void(*)(T*)
) but the value is not.
你的 SharedPtr 也是如此。
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.
当你用 std::function<void(T*)>
实例化 UniquePtr 时,你只会在编译时知道该类型,但不知道它所包装的函数对象的类型。
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.
这是真的。不要那样做。
Please help me to understand this paragraph.
仅仅因为一个唯一指针可以有一个在编译时已知的删除器,并不意味着它必须有这样的删除器。函数包装器既不是编译时删除器,也不是函数指针,因为它们具有运行时状态。
使用无状态删除器,例如 std::default_delete<T>
(或者可能是引用中提到的 DebugDelete,它可能也是无状态的)来获得编译时间优势。
在《C++ Primer, 5th Edition》中说,a shared_ptr
的删除器的类型直到运行时才知道,因为删除器不是直接存储为成员,而是作为一个可以指向删除器的指针。 unique_ptr
中删除器的类型在编译时是已知的,因为它是 unique_ptr
本身的一部分。
所以,我做了这个例子:
#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; }};
}
在我看来,
SharedPtr
中删除器的类型在编译时是已知的(void(*)(T*)
),但值不是。另一方面,
UniquePtr
中删除器的类型在编译时确实也是已知的,但值可能不是。所以书上说:
// 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.
如果 UniquePtr
中的删除器是指向函数的指针,但该指针是 nullptr
,则 del(p)
未定义。
请帮助我理解这一段。我实施 shared_ptr
和 unique_ptr
只是为了实践。
in my opinion, the type of the deleter in SharedPtr is known at compile time (
void(*)(T*)
) but the value is not.
你的 SharedPtr 也是如此。
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.
当你用 std::function<void(T*)>
实例化 UniquePtr 时,你只会在编译时知道该类型,但不知道它所包装的函数对象的类型。
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.
这是真的。不要那样做。
Please help me to understand this paragraph.
仅仅因为一个唯一指针可以有一个在编译时已知的删除器,并不意味着它必须有这样的删除器。函数包装器既不是编译时删除器,也不是函数指针,因为它们具有运行时状态。
使用无状态删除器,例如 std::default_delete<T>
(或者可能是引用中提到的 DebugDelete,它可能也是无状态的)来获得编译时间优势。