2015-07-09 11 views
6

Tôi đang di chuyển qua một vectơ có tự động (mã được đính kèm). Trong khi đi ngang qua, tôi cũng phụ thêm một số phần tử ở phía sau. Tôi đã không mong đợi đầu ra mà tôi nhận được.Hành vi bất thường với tính năng tự động khi di chuyển ngang qua một vector động

#include <iostream> 
#include <vector> 
using namespace std; 

vector <int> dynamic_vector; 

void access() 
{ 
    for (auto i : dynamic_vector) { 
     if (i == 3) { 
      dynamic_vector.push_back(4); 
      dynamic_vector.push_back(5); 
     } 
     cout << i << endl; 
    } 
} 

int main() { 
    dynamic_vector.push_back(1); 
    dynamic_vector.push_back(2); 
    dynamic_vector.push_back(3); 
    access(); 
    return 0; 
} 

Output:

1 
2 
3 

Tôi đã chờ đợi tất cả các số 1-5 sẽ được in ra. Tôi không thể hiểu cách di chuyển bằng tính năng tự động hoạt động như thế nào?

+0

Re * Tôi đã hy vọng tất cả các số từ 1 đến 5 sẽ được in * - Tôi mong đợi những con quỷ mũi, bản thân mình. Đây là hành vi không xác định, và ma quỷ mũi là kết quả kinh điển từ việc gọi hành vi không xác định. –

Trả lời

5

Điều này được gọi là Range-based for loop.

6.5.4 $ 1 Phạm vi có trụ sở tại tuyên bố [stmt.ranged]:

Trong mỗi trường hợp, một loạt trụ sở cho tuyên bố là tương đương với

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

Lưu ý mã giả tương đương, __end (và __begin) sẽ chỉ được đặt một lần khi bắt đầu vòng lặp. Trong trường hợp của bạn, sau push_back tại thời điểm cuối cùng của vòng lặp, các trình vòng lặp có thể không hợp lệ. Nếu có, sự gia tăng và tổng hợp trên chúng sẽ được thực hiện phụ thuộc. Điều đó có nghĩa, là một trong những khả năng, __end__begin sẽ vẫn giữ nguyên và số vòng lặp sẽ không thay đổi.

+1

Kết quả phụ thuộc vào việc triển khai cụ thể các trình vòng lặp.Ví dụ, trình vòng lặp có thể lưu trữ tham chiếu đến đối tượng vectơ và chỉ mục của phần tử thay vì chỉ lưu trữ một con trỏ. Trình lặp kết thúc có thể là một trình lặp vòng đặc biệt end_of_vector. –

+0

@AndreyNasonov Vâng, về cơ bản đây là vấn đề phụ thuộc triển khai. – songyuanyao

+0

@songyuanyao Có phải hành vi được xác định hoặc không xác định không? Đọc của tôi về tiêu chuẩn sẽ là UB, nhưng tôi không chắc chắn vì tôi không thể tìm thấy một định nghĩa tốt của iterator không hợp lệ. Điều tốt nhất tôi thấy là một trình vòng lặp không hợp lệ có thể là một trình lặp số ít và hỗ trợ các phép gán cơ bản. – Jens

5

Ngoài vấn đề được chỉ ra bởi câu trả lời của songyuanyao, mã bạn trình bày là hành vi không xác định. Đầu tiên, có thể là vectơ cần phải phân bổ lại vì một push_back, và sau đó tất cả các trình vòng lặp không hợp lệ và do đó gia tăng biến vòng lặp là hành vi không xác định.

Nhìn vào the documentation for push_back:

Nếu kích thước mới() là lớn hơn công suất() thì tất cả các vòng lặp và tài liệu tham khảo (bao gồm cả iterator qua-the-end) đều không còn giá trị. Nếu không, chỉ có trình vòng lặp kết thúc không hợp lệ.

, tôi sẽ nói rằng phụ thêm vào vector trong một phạm vi có trụ sở tại tuyên bố là hành vi không xác định trong mọi trường hợp, vì iterator cuối luôn không còn giá trị. Phạm vi dựa trên cho các cửa hàng một bản sao của end() -iterator ban đầu, và iterator này là không hợp lệ sau khi push_back đầu tiên. Điều này phù hợp với đầu ra của bạn, bởi vì nó vẫn trỏ đến phần đầu của phần tử ba phần tử. Tuy nhiên, bạn không nên dựa vào hành vi này.

Không may, tôi không thể tìm thấy định nghĩa cứng nhắc về ngữ nghĩa "trình lặp không hợp lệ" trong tiêu chuẩn. §24.2.1.11 nói rằng các trình vòng lặp không hợp lệ có thể là số ít, nhưng chỉ nói rằng dereferencing chúng có thể là hành vi không xác định. Không có ngữ nghĩa nào để so sánh chúng, nhưng với thực tế là một triển khai thực hiện vectơ là sử dụng địa chỉ bộ nhớ tiếp theo sau bộ nhớ trong và địa chỉ thay đổi khi véc-tơ phân bổ lại, tôi sẽ nói rằng vòng lặp là hành vi không xác định.

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