如何正确使用自定义shared_ptr删除程序?

德扬·尼科里奇

对于在shared_ptr中使用自定义删除器的正确方法,我仍然有些困惑。我有一个ResourceManager类,它可以跟踪资源分配,并且通过将Release方法设为私有,并修改了返回ResourceHolder的Allocate方法,修改了其接口以支持使用资源的自动释放:

// ResourceManager.cpp:
public:
    ResourceHolder<Resource> Allocate(args);

private:
    void Release(Resource*);

我实现的ResourceHolder类是这样的:

// ResourceHolder.h
template <typename T>
class ResourceHolder
{
public:
    ResourceHolder(
        _In_ T* resource,
        _In_ const std::function<void(T*)>& cleanupFunction)
        : _cleanupFunction(cleanupFunction)
        , _resource(resource, [&](T* resource)
        { 
            cleanup(resource); 
        }) // Uses a custom deleter to release the resource.
    {
    }

private:
    std::function<void(T*)> _cleanupFunction;
    std::shared_ptr<T> _resource;
};

// ResourceManager::Allocate()
...
return ResourceHolder<Resource>(new Resource(),[this](Resource* r) { Release(r); });
  1. 在我的清理方法中,是否必须删除T?这样做总是安全吗?

    if (nullptr != T) delete T;
    
  2. 如果cleanup()可以引发异常会怎样?在某些情况下,我可以让它逃脱范围吗?还是应该始终防止它发生?

  3. 我的ResourceManager不依赖于我正在使用的跟踪库,因此我选择了一个回调,调用者可以通过其构造函数提供该回调,并且该回调将在release方法中调用。所以我的发行版看起来像这样:

    void Release(Resource* r)
    {
        shared_ptr<std::Exception> exc = nullptr;
        try
        {
            // Do cleanup.
        }
        catch(Exception* ex)
        {
            exc.reset(ex);
        }
    
        if (nullptr != r) delete r;
    
        // Is it now safe to throw?
        if (nullptr != m_callback)
            m_callback(args, exc);
    }
    
    void Callback(args, shared_ptr<std::Exception> ex)
    {
        // Emit telemetry, including exception information.
    
        // If throwing here is ok, what is the correct way to throw exception here?
        if (nullptr != ex)
        {
            throw ex;
        }
    }
    

这是一种合理的设计方法吗?

船长

在我的清理方法中,是否必须删除T?这样做总是安全吗?

如果指针引用了实例化的对象,new则需要调用它,delete否则将导致内存泄漏和未定义的行为。

如果cleanup()可以引发异常会怎样?在某些情况下,我可以让它逃脱范围吗?还是应该始终防止它发生?

它不应该,您应该尽一切努力确保它不会。但是,如果清理代码确实引发了异常,则应捕获该异常,对其进行适当处理,然后将其吃掉原因是可以在析构函数的上下文中调用自定义删除程序,并且总是有可能在传播异常的同时调用析构函数。如果一个异常已经在处理中,并且引发了另一个未捕获的异常,则应用程序将终止。换句话说,将自定义删除器和清除代码视为析构函数,并遵循与异常处理相同的规则和准则。

有效的C ++项目#8-防止异常离开析构函数

析构函数永远不要发出异常。如果在析构函数中调用的函数可能抛出,则析构函数应捕获任何异常,然后将其吞下或终止程序。

§15.1 / 7 C ++标准[throw.except]

如果异常处理机制在完成要抛出的表达式的求值之后但在捕获异常之前调用了通过异常退出的函数std::terminate

--

这是一种合理的设计方法吗?

除了您目前打算如何处理异常外,我认为没有任何问题。您唯一需要做的真正更改是调用回调的方式以及回调如何处理传递给它的异常。更改后生成的代码可能类似于以下内容。

void Release(Resource* r)
{
    try
    {
        // Do cleanup.
    }
    catch (Exception& ex)
    {
        // Report to callback
        if (nullptr != m_callback)
            m_callback(args, &ex);

        // Handle exception completely or terminate

        // Done
        return;
    }

    // No exceptions, call with nullptr
    if (nullptr != m_callback)
        m_callback(args, nullptr);
}

void Callback(args, const Exception* ex)
{
    // Emit telemetry, including exception information.

    //  DO NOT RETHROW ex
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何安全地重载std :: unique_ptr的自定义删除程序?

为什么shared_ptr删除程序必须是CopyConstructible的?

将具有自定义删除器的unique_ptr移到shared_ptr

shared_ptr分配-是否也复制自定义删除程序?

std :: shared_ptr:带自定义删除器的typedef

具有自定义删除程序的std :: shared_ptr的Typedef别名

具有空值和自定义删除器的shared_ptr怪异

在shared_ptr的自定义删除器中检查nullptr是否有意义?

shared_ptr <>到数组自定义删除器(带有make_shared)

可以将std :: unique_ptr子类化以透明地应用自定义删除程序吗?

我是否在此通用unique_ptr <>()删除程序中正确使用了指针类?

铛-shared_ptr无法运行其删除程序

为什么带有shared_ptr的带有自定义删除器的unique_ptr不适用于nullptr?

boost:使用自定义删除程序序列化shared_ptr

具有std :: function的std :: shared_ptr作为自定义删除器和分配器

重置std :: shared_ptr是否会导致重置其删除程序?

Shared_ptr自定义删除器

配备有功能指针作为自定义删除器的unique_ptr是否与shared_ptr大小相同?

如何创建自定义的shared_ptr?

std :: unique_ptr的自定义删除程序是否是手动调用析构函数的有效位置?

Typedef一个带有静态自定义删除器的shared_ptr类型,类似于unique_ptr

Windows 10的自定义开始菜单-我可以删除程序列表吗?

shared_ptr删除程序问题

是否可以确保弱指针在std :: shared_ptr删除程序运行时已过期?

带有lambda自定义删除程序的std :: unique_ptr无法编译

使用自定义对象声明 shared_ptr 数组时出现错误 C2664

“<function-style-cast>”:在使用自定义删除器创建 shared_ptr 时无法从“初始化列表”转换为“std::shared_ptr<SDL_Window>”

shared_ptr<> 的自定义删除器给出“无上下文错误”

如何正确使用 std::shared_ptr 和 std::map