Подтвердить что ты не робот

Можно ли использовать циклический цикл С++ 11 с диапазоном rvalue-init?

Предположим, что у меня есть функция, которая возвращает значение std::vector по значению:

std::vector<int> buildVector();

Казалось бы естественным перебирать результат с использованием диапазона for:

for (int i : buildVector()) {
  // ...
}

Вопрос: Безопасно ли это сделать?

Мое чтение стандарта (на самом деле, черновик n4431) предполагает, что это может быть не так, хотя мне тяжело полагая, что комитет не смог разрешить это использование. Я надеюсь, что мое чтение неверно.

В разделе 6.5.4 определяется диапазон for:

for ( for-range-declaration : expression ) statement

со следующим обессериванием:

{
  auto && __range = range-init;
  for ( auto __begin = begin-expr,
             __end = end-expr;
        __begin != __end;
        ++__begin ) {
    for-range-declaration = *__begin;
    statement
  }
}

где range-init является просто ( expression ) и, по крайней мере, для типов классов, begin-expr является либо __range.begin(), либо begin(__range) и т.д.

В моем примере buildVector я думаю, что range-init создает временное значение, которое реализация может быть уничтожена сразу после привязки ссылки __range. Это означало бы, что ссылка __range может уже свисать с временем begin-expr.

Конечно, всегда должно быть безопасно написать это:

std::vector<int> notATemporary = buildVector();
for (int i : notATemporary) {
  // ...
}

Но я надеюсь, что мне не нужно добавлять это в свой список gotchas.

4b9b3361

Ответ 1

Да, это совершенно безопасно.

Из [class.temporary]/4-5:

Есть два контекста, в которых временные объекты уничтожаются в другой точке, чем конец fullexpression. Первый контекст - это когда конструктор по умолчанию называется [...]

Второй контекст - это когда привязка привязана к временному. Временное, на которое ссылается связанный или временный, являющийся полным объектом подобъекта, к которому привязана ссылка , сохраняется для времени жизни ссылки, за исключением:

  • Временная привязка к ссылочному элементу в конструкторах ctor-initializer [...]
  • Временная привязка к ссылочному параметру в вызове функции [...]
  • Время жизни временной привязки к возвращаемому значению в функции return statement [...]
  • Временная привязка к ссылке в new-initializer [...]

Ни одно из этих исключений не применяется. Временное, таким образом, сохраняется для времени существования ссылки, __range, который является целым циклом.