我尝试从p0052r2提案中实施unique_resource。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0052r2.pdf
提案中的构造函数声明为:
unique_resource(unique_resource&& rhs)
noexcept(is_nothrow_move_constructible_v<R> &&
is_nothrow_move_constructible_v<D>);
其中R是资源,D是删除器。
行为描述如下:
如果is_nothrow_move_constructible_v为true,则初始化资源 从forward(rhs.resource),否则从初始化资源 rhs.resource。[注意:如果资源构造抛出 exceptionrhs保留了资源的所有权,并将在适当时释放资源 时间。—尾注]如果is_nothrow_move_constructible_v为true 从forward(rhs.deleter)初始化Deleter,否则初始化 rhs.deleter的删除器。如果删除器的构造抛出 例外:如果!is_nothrow_move_constructible_v,则 rhs.deleter(资源)。
对此我有两个问题。
为什么我应该使用forward(rhs.resource)或rhs.resource而不是std :: move(rhs.resource)进行初始化。对于D也是一样。
如何正确实施异常处理?
仅当删除程序的构造函数抛出异常时,才应释放资源。
我目前有:
CUniqueResource(CUniqueResource&& rhs) try
: executeOnDestruction(rhs.executeOnDestruction)
, resource(std::move(rhs.resource))
, deleter(std::move(rhs.deleter))
{
rhs.release();
}
catch (...)
{
if constexpr(!std::is_nothrow_move_constructible_v<R>)
{
rhs.deleter(resource);
}
throw;
}
问题在于函数try块也包含了资源的构造。我该怎么做才能仅捕获deleter的异常,而无需引入对deleter的默认构造函数的调用。
编辑:
我想我根据eerorika的评论找到了第二个问题的答案。使用成员函数代替子对象。
代码如下:
CUniqueResource(CUniqueResource&& rhs)
: executeOnDestruction(rhs.executeOnDestruction)
, resource(std::move(rhs.resource))
, deleter(acquireDeleter(rhs))
{
rhs.release();
}
D acquireDeleter(CUniqueResource&& rhs)
{
try
{
return D(std::move(rhs.deleter));
}
catch(...)
{
if constexpr(!std::is_nothrow_move_constructible_v<R>)
{
rhs.deleter(this->resource);
}
throw;
}
}
我认为这应该可行,因为C ++保证返回值使用复制省略号。