С++, выделяющий shared_ptr с С++ 11 (std:: shared_ptr): Неправильно ли инициализировать shared_ptr во временную переменную?
Я читал этот ответ, и автор ссылается на повысить передовые методы в котором говорится:
Избегайте использования неназванных временного файла shared_ptr для сохранения ввода; посмотреть, почему это опасно, рассмотрите этот пример:
void f(shared_ptr<int>, int);
int g();
void ok() {
shared_ptr<int> p(new int(2));
f(p, g());
}
void bad() {
f(shared_ptr<int>(new int(2)), g());
}
Функция ok следует руководству по букве, тогда как плохая конструкция временного shared_ptr на месте, допуская возможность утечки памяти. поскольку аргументы функции оцениваются в неуказанном порядке, возможно для первого int (2), который будет оцениваться первым, g() второй, и мы никогда не сможем получить к конструктору shared_ptr, если g выбрасывает исключение. <... >
Проблема безопасности исключений, описанная выше, также может быть устранена используя функции make_shared или allocate_shared factory, определенные в повышение /make _shared.hpp. Эти функции factory также обеспечивают эффективность достигается за счет консолидации ассигнований.
Я предполагаю, что я начну использовать make_shared
, но мне было интересно, все еще ли эта рекомендация относится к С++ 11 shared_ptr
. Я спрашиваю, потому что я действительно не понимаю, почему это означает, что метать g()
не позволит вызвать вызов ctor.
Ответы
Ответ 1
Да, С++ 11 shared_ptr
работает одинаково.
Я спрашиваю, потому что я действительно не понимаю, почему это означает, что мета-вызов g() не позволит вызвать вызов ctor.
Что вы не понимаете? Это порядок операций, и стандарт не требует определенного порядка. Пусть распаковать оператор в последовательность выражений:
auto __temp = new int(2);
auto &&__temp2 = g();
auto __temp3 = shared_ptr<int>(__temp);
Вы видите проблему сейчас? Если g
выбрасывает, то __temp3
никогда не будет инициализироваться. Поэтому __temp
будет просочиться.
Стандарт С++ не требует, чтобы оператор был распакован таким образом. Но это тоже не запрещает. Компилятор допускает свободу упорядочивать эти независимые выражения, но считает нужным.
Ответ 2
Я не думаю, что что-то изменилось в отношении порядка оценки на С++ 11. То есть использование std::make_shared<T>(...)
является лучшим вариантом в отношении безопасности в дополнение к требованию только одного распределения памяти, а не двух.
В отношении того, что проблема: справедливо следующее утверждение аргумента f()
:
-
$tmp = new int(1)
(используя $tmp
, чтобы указать предоставленную компилятором временную переменную)
-
g()
-
std::shared_ptr<int>($tmp)
Теперь, если g()
бросает, оценка других частей никогда не выполняется, т.е. std::shared_ptr<int>
никогда не строится и $tmp
просачивается.