2015-05-26 11 views
22

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.

Trả lời

19

Có, nó hoàn toàn an toàn.

Từ [class.temporary]/4-5:

Có hai tình huống trong đó là tạm thời bị phá hủy tại một điểm khác biệt so với phần cuối của fullexpression. Ngữ cảnh đầu tiên là khi một hàm tạo mặc định được gọi là [...]

Ngữ cảnh thứ hai là khi tham chiếu bị ràng buộc tạm thời. Tạm thời mà tham chiếu là ràng buộc hoặc tạm thời mà là đối tượng hoàn toàn của một subobject mà tham chiếu được ràng buộc vẫn cho tuổi thọ của tài liệu tham khảo trừ:

  • Một tạm thời bị ràng buộc vào một tài liệu tham khảo thành viên trong ctor-initializer một constructor [...]
  • một tạm thời bị ràng buộc vào một tham số tham chiếu trong một cuộc gọi chức năng [...]
  • thời gian tồn tại của một tạm thời bị ràng buộc với giá trị trả về trong sự trở lại chức năng tuyên bố [...]
  • Tạm thời bị ràng buộc với tham chiếu trong trình khởi tạo mới [...]

Không có trường hợp ngoại lệ nào được áp dụng. Do đó, tạm thời tồn tại trong suốt thời gian tham chiếu, __range, là toàn bộ vòng lặp.

+2

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

+1

@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

+0

@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

Các vấn đề liên quan