清理C ++异常的析构函数中的代码

时间:2012-02-21 13:54:40

标签: c++ exception raii

我们可以使用异常的析构函数作为放置一些清理代码的地方吗?

通过这种方式,我们可以允许客户端控制完成步骤而不是RAII。 这是一个好的还是坏的设计? 这是OOP和C ++环境中的正确解决方案吗?

我目前正在开发一个异步程序,它本身就是异步启动多个任务。 模式如下:

struct IAsyncResult
{
    ...
    virtual void EndCall() const;
}
typedef std::shared_ptr<IAsyncResult> IAsyncResultPtr;

struct IAsyncTask
{
    virtual IAsyncResultPtr BeginTask() = 0;
    virtual void EndTask(IAsyncResultPtr async) const = 0;
}

class CompositeTask : public IAsyncTask
{
    …
}

不幸的是,我无法保证每个子任务的BeginTask方法都不会失败。因此,N-1子任务可能成功启动而第N个失败。

通常,在客户端代码完成之前确保没有后台任务正在运行至关重要。但有时客户并不关心某些任务是否失败。

所以我当前的解决方案涉及一个自定义异常,如果一个任务无法启动,它会从CompositeTask的BeginAsync方法抛出。这允许客户端控制清理阶段:

class composite_async_exception : public std::exception
{
    std::vector<IAsyncResultPtr> successfully_started_tasks;
    mutable bool manage_cleanup;
public:
    composite_async_exception(std::vector<IAsyncResultPtr> const& _successfully_started_tasks)
        : successfully_started_tasks(_successfully_started_tasks)
        , manage_cleanup(true)
    {
    }

    virtual ~composite_async_exception() throw()
    {
        if(!manage_cleanup)
            return;
        for( auto task = successfully_started_tasks.begin(); task != successfully_started_tasks.end(); ++task)
        {
            task->CancelTask();
        }
    }

    void Giveup() const throw()
    {
        manage_cleanup = false;
    }
};

客户端使用如下所示的代码:

try
{
    compositeTask.BeginAsync();
}
catch(composite_async_exception const& ex)
{
    //prevent the exception to cancel tasks
    ex.Giveup();
    // some handling
}

是否有一些最佳实践来处理这种情况?

1 个答案:

答案 0 :(得分:1)

  • 异常有资格被复制,析构函数将被多次调用。在你的情况下似乎没有问题。
  • 异常处理机制可能会通过销毁临时异常对象来中止您的任务,这些异常对象在抛出点处中止您的任务,而不是处理任务。

要验证这个应该读标准,我懒得做。