Я оставляю этот ответ здесь только для справки, в качестве примера ответа, который не был достаточно усердным в полном сценарии ОП. Так как сами ОП пересмотрели исключение и явно просто использовали предложение try / catch для предполагаемых RAII целей, не имея другого использования для него.
Ответ Николя Боласа - определенно правильный путь.
Оригинальный ответ:
Если все, что вы хотите убедиться, это то, что деструктор для _resource
вызывается в случае, если что-то идет не так , тогда у вас может быть Resource _resource
некоторый уникальный смарт-указатель, а затем сделать временный смарт-указатель в области ResourceConsumer::Initialize()
и, в конечном итоге, переместите темп на _resource
, если все пойдет хорошо. Во всех других сценариях область будет закрыта до перемещения, и разматывание стека вызовет соответствующий деструктор для временного.
Пример кода, в попытке максимально привязать ваш фрагмент к вопросу:
// resource consumer
class ResourceConsumer {
template<class T> using prop_ptr = std::experimental::propagate_const<std::unique_ptr<T>>;
prop_ptr<Resource> _resource;
// ...
public:
void Initialize(std::string name);
};
void ResourceConsumer::Initialize(std::string name) {
// first destroy _resource in-place
std::experimental::get_underlying(_resource).reset(); // See 'Note 2' below.
// then construct it in-place
auto tempPtr = std::make_unique<Resource>(name);
// do other things which may throw
// ...
// Initialization is done successfully, move the newly created one onto your member
_resource = move(tempPtr);
// we don't want to leave _resource initialized if anything goes wrong
// Fortunately, in case we didn't get here, tempPtr is already being destroyed after the next line, and _resource remains empty :-)
}
Примечание 1: Поскольку я понял, что предложение catch
только что перебрасывалось, мы получаем тот же эффект без него.
Примечание 2: Вы можете безопасно удалить вызов reset()
, если хотите, чтобы семантика исключений была такой, чтобы в случае неудачной инициализации не было сделано никаких изменений в resource . Это предпочтительный способ, a.k.a. Сильная гарантия исключения . В противном случае оставьте его там, чтобы гарантировать пустой ресурс в случае сбоя инициализации.
Примечание 3: Я использую оболочку propagate_ptr
вокруг unique_ptr
, чтобы сохранить const-квалификацию члена _resource
в const
пути доступа, т.е. при работе с const ResourceConsumer
. Не забудьте #include <experimental/propagate_const>
.