2012-02-21 27 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
  • 該異常有資格被複制,那麼析構函數會被多次調用。在你的情況下,似乎不成問題。
  • 異常處理機制可能會通過銷燬臨時異常對象來終止您的任務,而不是處理一個異常處理機制。

要驗證這一個應該讀標準,我懶得做。