对于在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); });
在我的清理方法中,是否必须删除T?这样做总是安全吗?
if (nullptr != T) delete T;
如果cleanup()可以引发异常会怎样?在某些情况下,我可以让它逃脱范围吗?还是应该始终防止它发生?
我的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] 删除。
我来说两句