Giả sử tôi có một hàm trả về một std::vector
theo giá trị:Có an toàn khi sử dụng vòng lặp C++ 11 dựa trên phạm vi rvalue-init không?
std::vector<int> buildVector();
Có vẻ như tự nhiên để lặp qua kết quả bằng cách sử dụng một loạt dựa trên for
: Câu hỏi
for (int i : buildVector()) {
// ...
}
: Có an toàn để làm như vậy?
Việc đọc tiêu chuẩn (thực tế, dự thảo n4431) gợi ý rằng có thể không, mặc dù tôi gặp khó khăn khi tin rằng ủy ban không cho phép sử dụng này. Tôi hy vọng rằng đọc của tôi là không chính xác.
Mục 6.5.4 xác định phạm vi dựa trên for
:
for (for-range-declaration : expression) statement
với desugaring sau:
{
auto && __range = range-init;
for (auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin) {
for-range-declaration = *__begin;
statement
}
}
nơi range-init
chỉ là (expression)
, và ít nhất đối với các loại lớp, begin-expr
là một trong hai __range.begin()
hoặc begin(__range)
, v.v.
Trong sốcủa tôiví dụ, tôi nghĩ rằng range-init
tạo ra tạm thời, việc thực hiện được phép hủy ngay sau khi tham chiếu __range
bị ràng buộc. Điều này có nghĩa là tham chiếu __range
có thể đã bị treo lơ lửng vào thời điểm begin-expr
được đánh giá.
Chắc chắn, nó sẽ luôn được an toàn để viết này:
std::vector<int> notATemporary = buildVector();
for (int i : notATemporary) {
// ...
}
Nhưng tôi hy vọng tôi không có để thêm video này vào danh sách của tôi về gotchas.
Một hình ảnh quan trọng sẽ cắn bạn nếu bạn bắt đầu chơi với các dải sau cùng: nếu bạn viết một bộ điều hợp phạm vi và nó được xây dựng từ một giá trị và bạn muốn có thể chuỗi nó trong một 'for (:)' biểu thức, bạn cần lưu trữ phạm vi đầu vào của bạn * theo giá trị *, vì tiện ích mở rộng cuộc đời tham chiếu không phải là chuyển tiếp. Lấy 'R &&', lưu trữ 'R'. – Yakk
@Yakk Yep, mặc dù [tôi đã thử cách khác] (http://stackoverflow.com/questions/29990045/temporary-lifetime-in-range-for-expression). Trong thực tế, bạn thậm chí đã trả lời rằng một :) – Barry
@yakk Thật vậy, đó là chính xác tình hình mà đã cho tôi suy nghĩ về điều này. – mbrcknl