2016-03-30 17 views
5

Dưới đây là một đoạn mã mà tôi đang tìm kiếm tại địa chỉ:Làm thế nào để lặp cập nhật sau khi phân bổ lại vector

vector<int> iv = {1,2,3,4,5,6,7,8,9,10}; 
auto iter = iv.begin(), mid = iv.begin() + iv.size()/2; 
for(int count = 100; count; --count) { 
    iter = iv.insert(iter, - 1); 
    cout << "capacity = " << iv.capacity() << "*mid = " << *mid << endl; 

} 

Theo quy định huỷ bỏ hiệu lực iterator:
vector: tất cả các vòng lặp và tài liệu tham khảo trước khi điểm chèn không bị ảnh hưởng, trừ khi kích thước vùng chứa mới lớn hơn dung lượng trước đó (trong trường hợp đó tất cả các trình vòng lặp và tham chiếu đều bị vô hiệu) [23.2.4.3/1] Iterator invalidation rules

Tôi hiểu rằng vì tôi gán lại giá trị "lặp" tại mỗi chèn hoạt động, có lẽ tôi có thể duy trì nó hợp lệ ity (xin vui lòng sửa tôi nếu tôi sai). Tuy nhiên, trình vòng lặp "giữa" vẫn hợp lệ trong trường hợp này ngay cả khi tôi không giả mạo nó trong vòng lặp và cũng khi khả năng của vectơ đang thay đổi.

Vì vậy, "trung bình" có thể tự cập nhật sau khi phân bổ lại như thế nào?

Để biết liệu giữa đang thay đổi ở tất cả hay không, tôi đã thay đổi dòng 4 trong mã để:

iv.insert(iter, -1); // Did not assign it back to iter. 

In kết quả của dereferencing giá trị ở giữa cho thấy sự thay đổi và có lẽ cũng ITER rằng không còn giá trị . (Một lần nữa, xin vui lòng sửa tôi nếu tôi sai).

+1

Tại sao bạn cho rằng "giữa" vẫn hợp lệ? Tôi đoán đó là bởi vì (* giữa) in '6', nhưng nó chỉ là một iterator lơ lửng trỏ đến một nơi nào đó trong bộ nhớ free'd mà không thay đổi giá trị trước đó được nêu ra. Nếu bạn chạy valgrind, bạn sẽ nhận được rất nhiều quyền truy cập không hợp lệ vào bộ nhớ. – kukyakya

Trả lời

3

Hiểu biết của bạn là chính xác. Khi công suất tăng lên, bất kỳ trình vòng lặp nào trở thành không hợp lệ. Trình biến đổi mid trở nên không hợp lệ ngay cả khi dung lượng không thay đổi nhưng về cơ bản chỉ đến phần tử trước đó.

Vì vậy, mã ban đầu sẽ hoạt động ít nhất cho iter, tuy nhiên mid sẽ trở thành không sử dụng được khi chèn lần đầu. Với việc sửa đổi mã hoàn toàn không hợp lệ.

Thông thường việc thực hiện vector trình lặp chỉ là một con trỏ đơn giản trỏ đến một phần tử để sao lưu mảng. Do đó khi thay đổi dung lượng và mảng được phân bổ lại, bất kỳ trình lặp nào như vậy không còn hợp lệ vì con trỏ trỏ tới không còn bộ nhớ hợp lệ nữa. Kết quả là, bạn có thể thấy một trong hai rác, bạn có thể nhận được lỗi phân đoạn hoặc ngẫu nhiên thấy các giá trị chính xác. Khi dung lượng không thay đổi, các phần tử trong mảng có thể được di chuyển về phía trước để bạn có thể thấy phần tử trước đó trong vòng lặp sau điểm chèn, nhưng chỉ trong trường hợp không có phần tử trống ở đầu mảng (ví dụ: start lớn hơn sau đó không). Nhưng tất cả những điều này đều cụ thể để triển khai và do đó, tiêu chuẩn nêu rõ rằng hầu hết các điều trên là hành vi không xác định.

+0

Có lý do gì không, tại sao điểm giữa với phần tử trước đó là 5 trong mã gốc ngay cả sau khi vô hiệu, nhưng giá trị ở giữa dường như thay đổi với sửa đổi cho đến khi lỗi phân đoạn. Có đúng không khi nói rằng giá trị giữa là một số giá trị rác hoặc kết quả mã là không thể đoán trước? – Satyabrat

+0

Sử dụng '* mid' sau' mid' đã bị vô hiệu là hành vi không xác định. Trong tình huống như vậy bạn có thể nhận được một giá trị có vẻ hợp lý, trông giống như rác hoặc treo chương trình của bạn. –

+0

@Satyabrat: Nó cụ thể để triển khai. Nhưng nói chung 'mid' chứa một con trỏ không thay đổi. Nhưng các phần tử di chuyển về phía trước khi chèn một cách logic đến con trỏ từ 'mid' sẽ được di chuyển phần tử trước đó. Nhưng như tôi đã nói, chỉ miễn là mảng sao lưu không được phân bổ lại (nghĩa là dung lượng không thay đổi). –

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