Я хотел бы попросить несколько советов относительно безопасности исключений. В частности, я ссылался Вы (действительно) пишете код безопасности исключений?. Если у меня есть контейнер указателей на объекты типа 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).
Это намного сложнее, чем нужно. Я бы начал так:
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
, затем поменяйте местами, затем уберите.
Я также читал в RAII, но я не знаю, как это будет работать, где мне нужен полиморфизм
Мой код выше опирается на RAII, полиморфизм не имеет значения. В приведенном выше коде нет необработанных указателей, которые не принадлежат типу RAII (кроме _nodes
, который вы должны изменить, чтобы быть std::vector<std::unique_ptr<Node>>
) поэтому, если выбрасывается исключение, все очищается, нет необходимости перехватывать исключение и выполнять очистку вручную.
Других решений пока нет …