我有一个STL容器,我需要对容器中的每个元素执行操作。但是如果操作在任何元素上失败,我想要反转已经更改过的任何元素的操作。
例如,如果我有一个STL向量,其指针指向一个数字bankAccount类,并希望将每一个增加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算法或使用反向迭代器?
答案 0 :(得分:9)
这就是我要做的事情:
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
内对象的指针通常不是一个好主意,因为容器期望存储在其中的数据具有值语义,而不是指针语义。这可能导致悬空指针,内存泄漏,还需要额外的清理代码,否则您不需要(手动删除容器中的项目)。使用上面的代码,我已经切换到将数据保存在向量中,如果这不是一个选项,则需要确保在复制向量时使用手动深层复制。
实际上,如果您对bankAccounts
和tmp
采用相同的定义,则可以将代码缩减为以下内容:
std::for_each(tmp.begin(), tmp.end(),
std::mem_fun_ref(&bankAccount::increaseBalance, 50));
bankAccounts.swap(tmp);
上述代码的主要优点是,在这两种情况下,如果没有任何进一步的特殊处理,它是异常安全的。
答案 1 :(得分:1)
我认为更优雅的方法是将操作视为交易。换句话说,创建帐户的替换副本,并在成功时覆盖原始文档。