У меня есть функция, для которой я хотел бы иметь сильную гарантию исключения:
class X {
/* Fields and stuff */
void some_function() {
vector1.push_back(/*...*/); // May Throw
vector2.push_back(/*...*/); // May Throw
vector3.push_back(/*...*/); // May Throw
vector4.push_back(/*...*/); // May Throw
}
};
Единственный способ, которым я могу думать о том, чтобы сделать это с сильной гарантией исключения, заключается в следующем:
class X {
/* Fields and stuff */
void some_function() {
try { vector1.push_back(/*...*/);};
catch (Vector1PushBackException) {
throw Vector1PushBackException;
}
try { vector2.push_back(/*...*/);};
catch (Vector2PushBackException) {
vector1.pop_back();
throw Vector2PushBackException;
}
try { vector3.push_back(/*...*/);};
catch (Vector3PushBackException) {
vector1.pop_back();
vector2.pop_back();
throw Vector3PushBackException;
}
try { vector4.push_back(/*...*/);};
catch (Vector4PushBackException) {
vector1.pop_back();
vector2.pop_back();
vector3.pop_back();
throw Vector4PushBackException;
}
}
};
Однако это действительно уродливо и подвержено ошибкам! Есть ли лучшее решение, чем то, что я указал выше? Я слышу, как кто-то говорит мне, что мне нужно использовать RAII, но я не могу понять, как это сделать, поскольку операции pop_back
не должны выполняться, когда функция возвращается нормально.
Я также хотел бы, чтобы любое решение было нулевым - накладные расходы на счастливом пути; Мне очень нужно, чтобы счастливый путь был как можно быстрее.
swap
после того, как будут выполнены опасные части. Это самое надежное решение. - person François Andrieux   schedule 13.04.2021catch
, который предназначен для повторного создания, вы можете просто использоватьthrow;
для повторного создания исключения. Это также единственный способ перебросить из универсального блокаcatch(...)
. - person François Andrieux   schedule 13.04.2021reserve
сначала, и если это не удается, тогда вы знаете и можете бросить, иначе вызовpush_back
должен быть хорошим. - person NathanOliver   schedule 13.04.2021push_back
, обратная функция проста. Вам просто нужноpop_back
(независимо от изменения емкости). Но рассмотрим функцию, которая выполняет более трудные для обратного действия операции, такие как изменение существующих элементов. Для этой проблемы нет универсального решения, кроме копирования/обмена (что не всегда возможно, поэтому не является полностью общим). В противном случае вам придется реализовать гарантию исключения вручную в соответствии с вашим уникальным вариантом использования. - person François Andrieux   schedule 13.04.2021try
/catch
на самом деле не на 100% бесплатны, скорее они просто не намного медленнее и будут иметь ненулевую стоимость по сравнению с отсутствием обработки ошибок вообще. Кроме того, то, что представляет собой приемлемые накладные расходы, является вопросом мнения или, по крайней мере, вопросом требований конкретного варианта использования. Я бы попробовалscope_guard
решение ниже и посмотреть, достаточно ли оно хорошо. - person François Andrieux   schedule 13.04.2021