gpt4 book ai didi

c++ - 如何正确使用自定义 shared_ptr 删除器?

转载 作者:太空狗 更新时间:2023-10-29 23:02:41 24 4
gpt4 key购买 nike

对于将自定义删除器与 shared_ptr 一起使用的正确方法,我仍然有些困惑。我有一个跟踪资源分配的 ResourceManager 类,我修改了它的接口(interface)以支持自动释放已用资源,方法是将 Release 方法设为私有(private),Allocate 方法返回一个 ResourceHolder:

// 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;
    }
    }

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

最佳答案

In my cleanup method, do I have to delete T? Is it always safe to do it?

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

What happens if cleanup() can throw an exception? Can I let it escape the scope under some circumstances, or should I always prevent it?

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

Effective C++第 8 项 - 防止异常离开析构函数

Destructors should never emit exceptions. If functions called in a destructor may throw, the destructor should catch any exceptions, then swallow them or terminate the program.

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

If the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught, calls a function that exits via an exception, std::terminate is called.

-

Is this a sound design approach?

除了您目前打算如何处理异常之外,我认为它没有任何问题。您需要做的唯一真正的改变是如何调用回调以及回调如何处理传递给它的异常。更改后的结果代码可能如下所示。

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
}

关于c++ - 如何正确使用自定义 shared_ptr 删除器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27743476/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com