在“C++ Primer,第5版”中,据说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
。 最佳答案
您的SharedPtr确实如此。
std::shared_ptr并非如此。
当使用std::function<void(T*)>
实例化UniquePtr时,您只会在编译时知道该类型,而不会知道它包装的函数对象的类型。
std::unique_ptr默认不使用std::function删除器。
这是真的。不要那样做
仅仅因为唯一指针可以在编译时知道一个删除器,并不意味着它必须具有这样的删除器。函数包装器不是函数指针,也不是编译时删除器,因为它们具有运行时状态。
使用像std::default_delete<T>
这样的无状态删除器(或者报价中提到的DebugDelete大概也是无状态的)来获得编译时的好处。
关于c++ - C++入门手册第5版:shared_ptr的删除器和unique_ptr的删除器之间的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64865906/