Почему boost не имеет make_scoped()?
Повышение-х make_shared()
функция обещает быть исключительной безопасностью при попытке создать shared_ptr
,
Почему нет make_scoped()
эквивалент? Есть ли распространенная лучшая практика?
Вот пример кода из boost::scoped_ptr
документация, которая мне кажется небезопасной:
boost::scoped_ptr<Shoe> x(new Shoe);
Эта строка кода будет выполнять эти три вещи по порядку:
- Выделите кучу памяти для
Shoe
- Вызовите конструктор для
Shoe
- Вызовите конструктор для
boost::scoped_ptr<Shoe>
Если конструктор для Shoe
выдает исключение, память будет просочиться. (см. ответ Р. Мартиньо Фернандеса) scoped_ptr
не будет обрабатывать освобождение, потому что оно еще не было построено.
Это недосмотр? Или есть решение, которое я не заметил?
3 ответа
Если конструктор дает сбой, память не просачивается. Это часть семантики new
, не задействованы умные указатели:
struct Foo { Foo() { throw 23; } };
new Foo(); // no memory leaked
Добавленная исключительная безопасность, обеспеченная make_shared
происходит, когда вы инициализируете два shared_ptr
s в выражении, и две инициализации не упорядочены, как в случае аргументов вызова функции:
struct Bar {
Bar(bool fail) {
if(fail) throw 17;
}
}
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false)));
Поскольку нет последовательности между оценками new Bar(true)
, shared_ptr<Bar>(new Bar(true))
, new Bar(false)
а также shared_ptr<Bar>(new Bar(false))
может произойти следующее:
new Bar(false)
оценивается и успешно выполняется: память выделяется;new Bar(true)
оценивается и дает сбой: он не теряет память в результате этой оценки;
нет shared_ptr
был построен в это время, и поэтому память, выделенная в #1, теперь просочилась.
scoped_ptr
предшествует движению семантики и не копируется по дизайну. Таким образом, make_scoped
было бы невозможно реализовать, потому что для возврата объекта из функции его тип должен быть подвижным или копируемым.
Если Shoe бросает, то Shoe не создается, поэтому scoped_ptr ничего не может сделать. Нет? Scoped_ptr x находится в стеке и будет очищен при выходе из области видимости.