2010-07-15 47 views
0

我有一個STL容器,我需要對容器中的每個元素執行一個操作。但是,如果操作在任何元素上失敗,我想要對已經更改的任何元素進行操作。迭代前進,然後通過STL容器反向

例如,如果我有一個指向bankAccount類的指針的STL向量,並希望每增加50美元。但是,如果任何一個銀行賬戶未能增加50個,我想完全取消增加,並且任何已經增加的賬戶減少50美元。

std::vector<bankAccount*> bankAccounts; 
std::vector<bankAccount*>::iterator iter; 

for (iter = bankAccounts.begin(); iter != bankAccounts.end(); ++iter) 
{ 
    try 
    { 
     iter->increaseBalance(50); 
    } 
    catch (...) 
    { 
     // One of the bankAccounts failed to increase by 50, now I need to go 
     // back and decrease by 50 all of the bankAccounts that have already 
     // been increased. 
    } 
} 

有沒有什麼優雅的方式來做到這一點?也許用STL算法或使用反向迭代器?

+1

編寫* functor *並使用* for_each * – 2010-07-15 18:50:49

+1

是否可以循環並檢查操作是否成功?那麼你只要確保他們都會成功,如果是的話,就執行這個動作。 – GManNickG 2010-07-15 18:59:29

+0

您應該捕獲您期望可能拋出的特定異常。如果你有一個catch(...)塊,你不知道拋出了什麼異常,離開這個catch塊的唯一明智的方法是重新拋出異常或終止應用程序。 – 2010-07-15 19:00:25

回答

9

這裏是我會做:

  • 移動循環
  • 外的try/catch創建bankAccounts容器
  • 遍歷重複容器的重複,在每個項目上調用increaseBalance
  • 如果循環成功完成,swap()原始和複製的容器

該代碼會是這個樣子:

std::vector<bankAccount> bankAccounts; 
... 
std::vector<bankAccount> tmp(bankAccounts); 

try 
{ 
    for (iter = tmp.begin(); iter != tmp.end(); ++iter) 
    { 
    iter->increaseBalance(50); 
    } 
    bankAccounts.swap(tmp); 
} 
catch (...) 
{ 
} 

請注意,拿着一個指向對象的std::vector內一般不是很好的主意,因爲容器希望存儲在其中的數據有值語義,不是指針語義。這可能會導致懸掛指針,內存泄漏,並且還需要額外的清理代碼,否則不需要(手動刪除容器中的項目)。使用上面的代碼,我已切換到在矢量中保存數據,如果這不是您需要的選項,以確保在複製矢量時使用了手動深度複製。

其實,如果你承擔相同的定義爲bankAccountstmp可以減少代碼如下:

std::for_each(tmp.begin(), tmp.end(), 
       std::mem_fun_ref(&bankAccount::increaseBalance, 50)); 
bankAccounts.swap(tmp); 

上面的代碼的主要優點是,在這兩種情況下,它是例外安全無進一步的特殊處理。

+0

將'for'替換爲'for_each'並將指針調用替換爲'mem_fun' – wheaties 2010-07-15 19:02:42

+0

您甚至不需要try/catch,除非您確實想要做其他事情。如果增加平衡在任何地方失敗,交換將不會發生。是的,我也會切換到for_each。 +1雖然。 – 2010-07-15 19:22:19

+0

是的,在這種情況下,'try/catch'並不是真的需要。我通常會完全放棄它,但我也嘗試重新構建OP的代碼,同時保留大部分代碼。 – 2010-07-15 19:25:33

1

我認爲一種更優雅的方法可以將操作當作交易處理。換句話說,創建帳戶的替代副本,並在成功時覆蓋原始副本。