2012-02-21 40 views
2

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

以这种方式,我们可以允许客户端控制终结步骤而不是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 
} 

是否有处理这种情况的最佳做法?

+0

一种可能性是具有ITaskProgress接口在其中可以给每个子任务的进度 类ITaskProgress { 公共: 空隙的UpdateProgress(<一些子任务标识>,布尔aSuccess,布尔&aContinue)= 0; }; 客户端可以实现此接口并注册并使用组合任务实例。现在,客户会收到通知,客户可以决定是否继续。 – PermanentGuest 2012-02-21 14:06:01

+0

我明白了,我的问题没有正确的表述。所以我改变了它。 – 2012-02-21 15:44:00

回答

1
  • 该异常有资格被复制,那么析构函数会被多次调用。在你的情况下,似乎不成问题。
  • 异常处理机制可能会通过销毁临时异常对象来终止您的任务,而不是处理一个异常处理机制。

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