将可释放对象封装到智能指针中

Wrapping a releaseable object into a smart pointer

本文关键字:智能 指针 封装 释放 对象      更新时间:2023-10-16

就我对智能指针的理解而言,它们的存在是为了避免内存泄漏等问题。然而,经常有一些对象也需要被释放,但不是由freedelete释放。是否有一些通用的方法使用这样的指针与模板?

FILE为例,完成后应使用fclose。当然,还有其他类型的指针,它们有自己独特的释放函数。那么,我是否必须实现单独的包装器来解释它们各自的发布方法,或者是否有更好的方法来做到这一点?

可以这样使用:

smart_ptr<FILE, fclose> fl = fopen();
smart_ptr<IStream, T->Release> pFileStream = SHCreateStreamOnFile(...);

如果您使用的是unique_ptrshared_ptr,您可以提供您的自定义删除器。unique_ptr的deleter作为模板参数传递,

Deleter必须是FunctionObject或FunctionObject的左值引用或函数的左值引用,可使用unique_ptr<T, Deleter>::pointer类型的参数调用

对于shated_ptr, deleter应该作为构造函数参数提供。

class Foo
{
};
class Deleter
{
public:
    void operator()(Foo *)
    {
        std::cout << "deleter";
    }
};
int main() {
    std::unique_ptr<Foo, Deleter> ptr(new Foo());
    std::shared_ptr<Foo> ptr1(new Foo(),
                             [](Foo*){std::cout << "deleter for shared_ptr";}
                             );
}

您必须小心不要引起内存泄漏。

shared_ptrunique_ptr都提供这种功能。


对于shared_ptr,构造函数是模板:

可以提供一个可选的deleter d,当没有shared_ptr对象拥有该对象时,该deleter d用于销毁该对象。默认情况下,使用类型Y的delete表达式作为删除符。

在这种情况下,删除器可以是任何可调用的可复制构造的,它们被类型擦除为可调用对象。

对于unique_ptr, deleter的类型是指针本身的类型形参:

template<
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;

在这种情况下没有擦除,并且提供给c-tor或重置的删除器实际上匹配删除器类型。

您可以使用自定义删除器构建shared_ptr(此处签名#3)和unique_ptr(此处签名#2)。

using T = ...;
auto deleter = [](T* x) { delete x; };
// different deleter - different unique_ptr type
// deleter is stored inline
auto x = std::unique_ptr<T, decltype(deleter)>(new T(...), deleter);
// same shared_ptr<T> type regardless of the deleter type,
// deleter is stored in the "shared state"
auto y = std::shared_ptr<T>(new T(...), deleter);

注意,make_shared()不能用来构造带有自定义删除器的shared_ptr