0

我想请教一些关于异常安全的建议。特别是我一直在参考你(真的)写异常安全代码吗?. 如果我有一个指向类型对象的指针容器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)。

4

1 回答 1

1

这比它需要的复杂得多。我会这样开始:

std::vector<std::unique_ptr<Node>> nodes(10);    
for (auto& p : nodes)
    p.reset(new Node());

如果构造向量或分配一个Nodethrows,那么一切都会被自动清理。

现在,如果您明智并替换_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,然后交换,然后清理。

我也一直在阅读 RAII,但我不知道这在我需要多态性的地方如何工作

我上面的代码依赖于 RAII,多态性是无关紧要的。上面的代码中没有不属于 RAII 类型的原始指针(除了 in _nodes,您应该将其更改为 be std::vector<std::unique_ptr<Node>>),因此如果抛出异常,所有内容都会被清理,无需捕获异常并手动执行清理。

于 2014-03-16T20:24:10.310 回答