2010-07-15 64 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

我认为一种更优雅的方法可以将操作当作交易处理。换句话说,创建帐户的替代副本,并在成功时覆盖原始副本。