Хрупкость композиции при реализации операторов с учетом гарантии исключений
Скажите, пожалуйста, правильно ли я понимаю следующее.
У меня есть тип A. Предположим, что я хочу реализовать для такого типа оператор A& operator=(const A& a) со строгой гарантией относительно исключений. То есть, в случае отказа, оператор исключение кидает, но объект типа A остается в исходном состоянии.
Проблема - тип A содержит много полей, которые в свою очередь состоят из других полей, и где-то там внутри есть поле типа Z. Тысячи лет тип Z обеспечивал строгую гарантию относительно исключений своего оператора Z& operator=(const Z& z), но вот одним ужасным днем эта гарантия была разрушена, и никто этого не увидел.
Вопросы следующие.
- Действительно композиция настолько хрупка?
- Как обнаружить, что поле типа
Zстало нарушать гарантии того, что в рамках выполнения оператораA& operator=(const A& a)во всех цепочках операций обеспечивается строгая гарантия исключений? - Можно ли побороть эту хрупкость, если вместо композиции значений уйти в сторону композиции указателей (умных)? Ведь в таком случае объекты можно копировать путем вызова метода
Type::Uptr Type::Clone() const. Перемещение реализовать еще проще - достаточно поменять значение указателя. Мне кажется, что это намного проще анализировать и отслеживать, но уверенности у меня в этом нет.
Ответы (1 шт):
Да, вы правы: умный указатель даёт гарантию даже не опираясь на гарантии полей. Сам класс A с указателем сохраняет тот же интерфейс что и реализация без указателя:
class A {
public:
A& operator=(const A& a) {
impl.reset(new Impl(*a.impl));
return *this;
}
private:
struct Impl {
Z z;
};
std::unique_ptr<Impl> impl;
};