Идиома исключительной безопасности, относящаяся к параметрам конструктора

Я искал некоторый код, над которым я работаю, и у нас есть эквивалент этого:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Detach());

Где AutoPtr — наша версия auto_ptr, а Detach () возвращает собственный указатель и сбрасывает себя. Также B () становится владельцем x.

Теперь я понял, что это приведет к утечке x, если new сгенерирует std :: bad_alloc, поэтому я изменил код так:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Get());
x.Detach();

Но потом я понял, что если B () «владеет» указателем, и во время его создания возникает исключение, он должен позаботиться об удалении самого параметра (или он должен быть?), Так что x будет удален дважды, один раз с помощью B () и один раз деструктором х.

Теперь, есть ли идиома C ++, которая решает эту проблему, например, делает код, который вызывает конструкторов, ответственных за очистку параметров? Кажется, большая часть кода, который я видел, не делает этого …

3

Решение

Кажется, очевидным решением является временный AutoPtr<A> конструктору B:

AutoPtr<B> y(new B(AutoPtr<A>(x));

(это также добавляет контроль ресурсов для B* вернулся из new B()).

Bконструктор позвонит x.Detach() инициализировать все, что нужно для инициализации с A*, Если исключение происходит в любой момент, AutoPtr<A> выпустит объект.

Если вы хотите сохранить A объект управляется x в случае исключения вы можете передать AutoPtr<A>& конструктору B вместо.

3

Другие решения

…он должен позаботиться об удалении самого параметра (или должен?)

Нет, не должно.

B не существует, пока конструктор не завершится, и если он не существует, он не должен претендовать на владение чем-либо (в какой-то степени; если сам конструктор что-то сделал, это также должно быть безопасным).

Идиома C ++ — не использовать необработанные указатели для владения (в том числе для y)! B должен принять AutoPtr в качестве аргумента, так что вызывающая сторона может отказаться от владения этим способом. Это цель std::unique_ptr а также std::move:

std::unique_ptr<A> x;

std::unique_ptr<B> y(new B(std::move(x)));

Также обратите внимание, что на самом деле new не следует использовать так же; вместо этого используйте make_* коммунальные услуги:

auto y = std::make_unique<B>(std::move(x));

Но это отсутствует в настоящее время в качестве надзора.

3

Примерно так, может быть:

B* y = new B();
y->Attach(x.Detach());

или же

B* y = new B();
(*y) = x;
0
По вопросам рекламы [email protected]