我想就异常安全问一些建议。特别是我一直在引用Do you (really) write exception safe code?。如果我有一个指向Node
类型对象的指针容器,并且我要清除并重新初始化具有新对象集合的对象容器_nodes
,那么这段代码是否会异常安全?
std::vector<Node*> nodes;
for (int i = 0; i < 10; i++)
{
try
{
// New can throw an exception. We want to make sure that if an exception is thrown any allocated memory is deleted.
std::unique_ptr<Node> node(new Node());
Node* n = node.get();
nodes.push_back(n);
node.release();
}
catch (std::exception& exception)
{
// If an exception is thrown, rollback new allocations and rethrow the exception.
for (std::vector<Node*>::iterator it = nodes.begin(); it < nodes.end(); it++)
{
delete *it;
}
nodes.clear();
throw exception;
}
}
_nodes.swap(nodes);
// Delete the unused (previous) objects from the swapped container.
for (std::vector<Node*>::iterator it = nodes.begin(); it < nodes.end(); it++)
{
delete *it;
}
我也一直在阅读RAII,但我不知道在需要多态性(http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping)的情况下这是如何工作的。
答案 0 :(得分:1)
这比它需要的要复杂得多。我会这样开始:
std::vector<std::unique_ptr<Node>> nodes(10);
for (auto& p : nodes)
p.reset(new Node());
如果构建向量或分配Node
投掷,那么所有内容都将自动清理。
现在,如果您明智并将_nodes
替换为std::vector<std::unique_ptr<Node>>
,那么该功能的其余部分就是:
_nodes.swap(nodes);
否则它不那么简单:
std::vector<Node*> nodes2;
nodes2.reserve(nodes.size());
for (auto p : nodes)
nodes2.push_back(p.release());
_nodes.swap(nodes2);
for (auto p : nodes2)
delete p;
假设Node
析构函数不能抛出,这里唯一可以抛出的就是reserve
调用,所以如果抛出nodes
因为它保持unique_ptr
nodes2
1}}对象。之后,您可以安全地将所有权转移到_nodes
,然后交换,然后清理。
我也读过RAII,但我不知道在需要多态性的情况下这是如何工作的
我上面的代码依赖于RAII,多态性无关紧要。上面的代码中没有原始指针,它们不属于RAII类型(std::vector<std::unique_ptr<Node>>
除外,您应该将其更改为{{1}})所以如果抛出异常,一切都会被清理掉,那里不需要捕获异常并进行手动清理。