Предположим, что у меня есть функция, которая возвращает значение 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.