С++, выделяющий 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 просачивается.