Quy tắc vô hiệu hóa vòng lặp


543

Các quy tắc vô hiệu hóa vòng lặp cho các thùng chứa C ++ là gì?

Tốt nhất là trong một định dạng danh sách tóm tắt.

(Lưu ý: Đây có nghĩa là một mục trong Câu hỏi thường gặp về C ++ của Stack Overflow . Nếu bạn muốn phê bình ý tưởng cung cấp Câu hỏi thường gặp trong biểu mẫu này, thì bài đăng trên meta bắt đầu tất cả điều này sẽ là nơi để thực hiện điều đó. câu hỏi đó được theo dõi trong phòng chat C ++ , nơi ý tưởng FAQ bắt đầu ngay từ đầu, vì vậy câu trả lời của bạn rất có thể được đọc bởi những người nghĩ ra ý tưởng.)


Các câu trả lời có nên có cùng định dạng với câu trả lời của bạn không?
PW

@PW IMO sẽ được ưu tiên cho tính đối xứng nhưng tôi không thể thực thi nó: P
Các cuộc đua nhẹ nhàng trong quỹ đạo

Còn c ++ 20 thì sao?
Walter

1
@Walter Chưa tồn tại;)
Các cuộc đua nhẹ nhàng trong quỹ đạo

Câu hỏi này là, để trích dẫn Leela từ Futurama, từ thời đại ngu ngốc, và theo ý kiến ​​khiêm tốn của tôi nên bị bỏ ngỏ.
Roman Luštrik

Câu trả lời:


112

C ++ 17 (Tất cả các tài liệu tham khảo là từ bản thảo làm việc cuối cùng của CPP17 - n4659 )


Chèn

Trình tự container

  • vector: Các chức năng insert, emplace_back, emplace, push_backnguyên nhân phân bổ lại nếu kích thước mới lớn hơn công suất cũ. Việc tái phân bổ làm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp tham chiếu đến các phần tử trong chuỗi. Nếu không có sự phân bổ lại xảy ra, tất cả các trình lặp và tham chiếu trước điểm chèn vẫn còn hiệu lực. [26.3.11.5/1]
    Đối với reservechức năng, việc phân bổ lại làm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp tham chiếu đến các phần tử trong chuỗi. Không có sự phân bổ lại sẽ diễn ra trong các lần chèn xảy ra sau một cuộc gọi reserve()đến thời điểm khi chèn sẽ làm cho kích thước của vectơ lớn hơn giá trị của capacity(). [26.3.11.3/6]

  • deque: Một chèn vào giữa deque làm mất hiệu lực tất cả các trình vòng lặp và tham chiếu đến các phần tử của deque. Việc chèn vào một trong hai đầu của deque làm mất hiệu lực tất cả các trình vòng lặp cho deque, nhưng không có ảnh hưởng đến tính hợp lệ của các tham chiếu đến các phần tử của deque. [26.3.8.4/1]

  • list: Không ảnh hưởng đến tính hợp lệ của các trình vòng lặp và tham chiếu. Nếu một ngoại lệ được ném ra, không có hiệu ứng. [26.3.10.4/1].
    Các insert, emplace_front, emplace_back, emplace, push_front, push_backchức năng được bảo hiểm theo quy tắc này.

  • forward_list: Không có sự quá tải nào insert_aftersẽ ảnh hưởng đến hiệu lực của các trình lặp và tham chiếu [26.3.9.5/1]

  • array: Theo quy định , các trình vòng lặp cho một mảng không bao giờ bị vô hiệu trong suốt vòng đời của mảng. Tuy nhiên, ta cần lưu ý rằng trong quá trình trao đổi, iterator sẽ tiếp tục trỏ đến cùng một phần tử mảng và do đó sẽ thay đổi giá trị của nó.

Liên kết container

  • All Associative Containers: Các insertemplacecác thành viên sẽ không ảnh hưởng đến tính hợp lệ của vòng lặp và tài liệu tham khảo để container [26.2.6 / 9]

Container không liên kết

  • All Unordered Associative Containers: Việc làm lại không hợp lệ các trình vòng lặp, thay đổi thứ tự giữa các phần tử và thay đổi các phần tử xô xuất hiện trong, nhưng không làm mất hiệu lực các con trỏ hoặc tham chiếu đến các phần tử. [26.2.7 / 9]
    Các thành viên insertemplacecác thành viên sẽ không ảnh hưởng đến tính hợp lệ của các tham chiếu đến các phần tử vùng chứa, nhưng có thể làm mất hiệu lực tất cả các trình vòng lặp đến vùng chứa. [26.2.7 / 14]
    Các thành viên insertemplacecác thành viên sẽ không ảnh hưởng đến tính hợp lệ của các trình vòng lặp nếu (N+n) <= z * B, trong đó Nsố phần tử trong vùng chứa trước thao tác chèn, nlà số phần tử được chèn, Blà số lượng thùng chứa và zlà hệ số tải tối đa của container. [26.2.7 / 15]

  • All Unordered Associative Containers: Trong trường hợp hoạt động hợp nhất (ví dụ a.merge(a2):), các trình vòng lặp đề cập đến các phần tử được chuyển và tất cả các trình vòng lặp tham chiếu asẽ bị vô hiệu, nhưng các trình vòng lặp cho các phần tử còn lại a2sẽ vẫn còn hiệu lực. (Bảng 91 - Yêu cầu container liên kết không có thứ tự)

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Xóa

Trình tự container

  • vector: Các chức năng erasepop_backvô hiệu hóa các trình lặp và tham chiếu tại hoặc sau điểm xóa. [26.3.11.5/3]

  • deque: Một thao tác xóa sẽ xóa phần tử cuối cùng của một dequebộ lặp chỉ vô hiệu hóa và tất cả các bộ lặp và tham chiếu đến các phần tử bị xóa. Một hoạt động xóa sẽ xóa phần tử đầu tiên của một phần tử dequenhưng không phải phần tử cuối cùng chỉ làm mất hiệu lực các trình lặp và tham chiếu đến các phần tử bị xóa. Một hoạt động xóa không xóa phần tử đầu tiên cũng như phần tử cuối cùng của một dequetrình vòng lặp quá khứ và tất cả các trình vòng lặp và tham chiếu đến tất cả các phần tử của deque. [Lưu ý: pop_frontpop_backđang xóa các hoạt động. Ghi chú của người phụ nữ] [26.3.8.4/4]

  • list: Chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa. [26.3.10.4/3]. Này áp dụng cho erase, pop_front, pop_back, clearchức năng.
    removevà các remove_ifhàm thành viên: Xóa tất cả các thành phần trong danh sách được gọi bởi một trình lặp danh sách imà các điều kiện sau giữ: *i == value, pred(*i) != false. Chỉ vô hiệu hóa các trình lặp và tham chiếu đến các phần tử bị xóa [26.3.10.5/15].
    uniquehàm thành viên - Xóa tất cả trừ phần tử đầu tiên khỏi mọi nhóm phần tử bằng nhau liên tiếp được lặp lại bởi iterator itrong phạm vi (đối với phiên bản duy nhất có đối số vị ngữ). Chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa. [26.3.10.5/19][first + 1, last)*i == *(i-1)(đối với phiên bản độc đáo với không có đối số) hoặcpred(*i, *(i - 1))

  • forward_list: erase_aftersẽ chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa. [26.3.9.5/1].
    removevà các remove_ifhàm thành viên - Xóa tất cả các thành phần trong danh sách được gọi bởi một trình lặp danh sách i mà các điều kiện sau giữ: *i == value(for remove()), pred(*i)là true (for remove_if()). Chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa. [26.3.9.6/12].
    uniqueHàm thành viên - Xóa tất cả trừ phần tử đầu tiên khỏi mọi nhóm phần tử bằng nhau liên tiếp được lặp lại bởi iterator i trong phạm vi [đầu tiên + 1, cuối cùng) mà *i == *(i-1)(đối với phiên bản không có đối số) hoặc pred(*i, *(i - 1))(đối với phiên bản có biến vị ngữ đối số) giữ. Chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa. [26.3.9.6/16]

  • All Sequence Containers: clearlàm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp đề cập đến các phần tử của a và có thể làm mất hiệu lực của trình vòng lặp quá khứ (Bảng 87 - Yêu cầu bộ chứa chuỗi). Nhưng đối với forward_list, clearkhông làm mất hiệu lực các vòng lặp quá khứ. [26.3.9.5 / 32]

  • All Sequence Containers: assignlàm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp đề cập đến các thành phần của vùng chứa. Cho vectordeque, cũng làm mất hiệu lực của trình vòng lặp quá khứ. (Bảng 87 - Yêu cầu bộ chứa tuần tự)

Liên kết container

  • All Associative Containers: Các erasethành viên sẽ chỉ vô hiệu hóa các trình vòng lặp và tham chiếu đến các phần tử bị xóa [26.2.6 / 9]

  • All Associative Containers: Các extractthành viên chỉ vô hiệu hóa các trình vòng lặp cho phần tử bị loại bỏ; con trỏ và tham chiếu đến phần tử bị loại bỏ vẫn còn hiệu lực [26.2.6 / 10]

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Yêu cầu chung về container liên quan đến vô hiệu hóa vòng lặp:

  • Trừ khi có quy định khác (rõ ràng hoặc bằng cách xác định hàm theo các hàm khác), việc gọi hàm thành viên vùng chứa hoặc chuyển một vùng chứa làm đối số cho hàm thư viện sẽ không làm mất hiệu lực các trình lặp trong hoặc thay đổi giá trị của các đối tượng trong vùng chứa đó . [26.2.1 / 12]

  • không có swap()chức năng nào làm mất hiệu lực bất kỳ tham chiếu, con trỏ hoặc trình vòng lặp nào đề cập đến các phần tử của các container được hoán đổi. [Lưu ý: Trình lặp end () không tham chiếu đến bất kỳ phần tử nào, vì vậy nó có thể bị vô hiệu. Ghi chú của người phụ nữ] [26.2.1 / (11.6)]

Như ví dụ về các yêu cầu trên:

  • transformthuật toán: Các hàm opbinary_opsẽ không làm mất hiệu lực các trình vòng lặp hoặc các phần phụ hoặc sửa đổi các phần tử trong phạm vi [28.6.4 / 1]

  • accumulatethuật toán: Trong phạm vi [đầu tiên, cuối cùng], binary_opsẽ không sửa đổi các phần tử cũng như không hợp lệ các trình lặp hoặc phụ [29.8.2 / 1]

  • reducethuật toán: binary_op sẽ không làm mất hiệu lực các trình vòng lặp hoặc các phần phụ, cũng không sửa đổi các phần tử trong phạm vi [đầu tiên, cuối cùng]. [29.8.3 / 5]

và như thế...



2
@LightnessRacesinOrbit: Đã thử làm theo định dạng câu trả lời ban đầu của bạn. :)
PW

1
chúng ta cũng có thể có một danh sách cho std::string? Tôi nghĩ nó khác với std::vectordo SSO
sp2danny

1
@ sp2danny: Do SSO, stringkhông đạt yêu cầu chung thứ hai được liệt kê ở trên. Vì vậy, tôi đã không bao gồm nó. Cũng đã cố gắng bám vào cùng một mẫu của các mục FAQ trước đó.
PW

@LightnessRaceswithMonica Cảm ơn các bạn đã làm việc chăm chỉ. Tôi có một câu hỏi làm tôi bối rối trong nhiều ngày. "Vô hiệu" chính xác có nghĩa là gì trên các bối cảnh này? Có nghĩa "invalidated" can mean "no longer points to what it used to", not just "may not point to any valid element"là @Marshall Clow được mô tả trong câu trả lời này ? Hoặc nó chỉ chỉ 1 trong 2 điều khoản?
Rick

410

C ++ 03 (Nguồn: Quy tắc xác thực Iterator (C ++ 03) )


Chèn

Container tuần tự

  • vector: tất cả các trình lặp và tham chiếu trước đ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 lặp và tham chiếu đều bị vô hiệu) [23.2.4.3/1]
  • deque: tất cả các trình lặp và tham chiếu đều bị vô hiệu, trừ khi thành viên được chèn ở cuối (trước hoặc sau) của deque (trong trường hợp đó tất cả các trình lặp đều bị vô hiệu, nhưng tham chiếu đến các phần tử không bị ảnh hưởng) [23.2.1.3/1]
  • list: tất cả các trình lặp và tham chiếu không bị ảnh hưởng [23.2.2.3/1]

Container liên kết

  • [multi]{set,map}: tất cả các trình lặp và tham chiếu không bị ảnh hưởng [23.1.2 / 8]

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Xóa

Container tuần tự

  • vector: mọi lặp và tham chiếu sau khi xóa điểm bị vô hiệu [23.2.4.3/3]
  • deque: tất cả các trình lặp và tham chiếu đều bị vô hiệu, trừ khi các thành viên bị xóa ở cuối (trước hoặc sau) của deque (trong trường hợp đó chỉ các trình lặp và tham chiếu đến các thành viên bị xóa là vô hiệu) [23.2.1.3/4]
  • list: chỉ các trình lặp và tham chiếu đến phần tử bị xóa là không hợp lệ [23.2.2.3/3]

Container liên kết

  • [multi]{set,map}: chỉ các trình lặp và tham chiếu đến các phần tử bị xóa là không hợp lệ [23.1.2 / 8]

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Thay đổi kích thước

  • vector: theo chèn / xóa [23.2.4.2/6]
  • deque: theo chèn / xóa [23.2.1.2/1]
  • list: theo chèn / xóa [23.2.2.2/1]

Lưu ý 1

Trừ khi có quy định khác (rõ ràng hoặc bằng cách xác định hàm theo các hàm khác), việc gọi hàm thành viên vùng chứa hoặc chuyển một vùng chứa làm đối số cho hàm thư viện sẽ không làm mất hiệu lực các trình lặp trong hoặc thay đổi giá trị của các đối tượng trong vùng chứa đó . [23.1 / 11]

Lưu ý 2

Không rõ ràng trong C ++ 2003, liệu các trình lặp "kết thúc" có tuân theo các quy tắc trên hay không ; dù sao bạn cũng nên cho rằng chúng là như vậy (vì đây là trường hợp thực tế).

Lưu ý 3

Các quy tắc về vô hiệu hóa con trỏ là các quy tắc như vô hiệu hóa các tham chiếu.


5
Ý kiến ​​hay, chỉ cần nhận xét: Tôi nghĩ rằng các thùng chứa kết hợp có thể được xếp lại với nhau trong một dòng duy nhất, và nó có thể có giá trị sau đó thêm một dòng khác của các liên kết không có thứ tự ... mặc dù tôi không chắc phần làm lại có thể như thế nào được ánh xạ trên insert / erase, bạn có biết một cách để kiểm tra xem liệu một bản phát lại sẽ được kích hoạt hay không?
Matthieu M.

1
IIRC, ở đâu đó thông số kỹ thuật nói rằng trình lặp cuối không phải là trình lặp "đối với các đối tượng trong vùng chứa đó". Tôi tự hỏi làm thế nào những đảm bảo tìm kiếm iterator cuối trong mỗi trường hợp?
Julian Schaub - litb

1
@MuhammadAnnaqeeb: Câu trả lời này được thừa nhận là không rõ ràng, vì tôi đã chọn một phím tắt, nhưng ý định là nói thay đổi kích thước chèn / xóa, vì nếu cần phải phân bổ lại, bạn có thể coi đó là giống như xóa sau đó chèn lại tất cả các yếu tố bị ảnh hưởng. Phần đó của câu trả lời chắc chắn có thể được cải thiện.
Các cuộc đua nhẹ nhàng trong quỹ đạo

1
@Yakk: Nhưng nó không; xem văn bản tiêu chuẩn được trích dẫn. Có vẻ như điều đó đã được sửa trong C ++ 11. :)
Các cuộc đua nhẹ nhàng trong quỹ đạo

1
@metamorphosis: deque lưu trữ dữ liệu trong các khối không liền kề. Chèn vào đầu hoặc cuối có thể phân bổ một khối mới, nhưng nó không bao giờ di chuyển xung quanh các phần tử trước đó, vì vậy con trỏ vẫn còn hiệu lực. Nhưng các quy tắc để đi đến phần tử tiếp theo / trước thay đổi nếu một khối mới được phân bổ, do đó các trình vòng lặp bị vô hiệu.
Nick Matteo

357

C ++ 11 (Nguồn: Quy tắc xác thực Iterator (C ++ 0x) )


Chèn

Container tuần tự

  • vector: tất cả các trình lặp và tham chiếu trước đ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 lặp và tham chiếu đều bị vô hiệu) [23.3.6.5/1]
  • deque: tất cả các trình lặp và tham chiếu đều bị vô hiệu, trừ khi thành viên được chèn ở cuối (trước hoặc sau) của deque (trong trường hợp đó tất cả các trình lặp đều bị vô hiệu, nhưng tham chiếu đến các phần tử không bị ảnh hưởng) [23.3.3.4/1]
  • list: tất cả các trình lặp và tham chiếu không bị ảnh hưởng [23.3.5.4/1]
  • forward_list: tất cả các trình lặp và tham chiếu không bị ảnh hưởng (áp dụng cho insert_after) [23.3.4.5/1]
  • array: (không có)

Container liên kết

  • [multi]{set,map}: tất cả các trình lặp và tham chiếu không bị ảnh hưởng [23.2.4 / 9]

Container liên kết chưa được sắp xếp

  • unordered_[multi]{set,map}: tất cả các trình vòng lặp bị vô hiệu hóa khi diễn tập lại xảy ra, nhưng các tham chiếu không bị ảnh hưởng [23.2.5 / 8]. Việc làm lại không xảy ra nếu việc chèn không làm cho kích thước của thùng chứa vượt quá z * Bđâu zlà hệ số tải tối đa và Bsố lượng xô hiện tại. [23.2.5 / 14]

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Xóa

Container tuần tự

  • vector: mọi lặp và tham chiếu tại hoặc sau điểm xóa bị vô hiệu [23.3.6.5/3]
  • deque: xóa phần tử cuối cùng chỉ vô hiệu hóa các trình vòng lặp và các tham chiếu đến các phần tử bị xóa và trình vòng lặp quá khứ; xóa phần tử đầu tiên chỉ làm mất hiệu lực các trình vòng lặp và các tham chiếu đến các phần tử bị xóa; xóa bất kỳ phần tử nào khác làm mất hiệu lực tất cả các trình lặp và tham chiếu (bao gồm cả trình vòng lặp quá khứ) [23.3.3.4/4]
  • list: chỉ các trình lặp và tham chiếu đến phần tử bị xóa là không hợp lệ [23.3.5.4/3]
  • forward_list: chỉ các trình vòng lặp và tham chiếu đến phần tử bị xóa là không hợp lệ (áp dụng cho erase_after) [23.3.4.5/1]
  • array: (không có)

Container liên kết

  • [multi]{set,map}: chỉ các trình lặp và tham chiếu đến các phần tử bị xóa là không hợp lệ [23.2.4 / 9]

Container liên kết không có thứ tự

  • unordered_[multi]{set,map}: chỉ các trình lặp và tham chiếu đến các phần tử bị xóa là không hợp lệ [23.2.5 / 13]

Bộ điều hợp container

  • stack: được kế thừa từ container bên dưới
  • queue: được kế thừa từ container bên dưới
  • priority_queue: được kế thừa từ container bên dưới

Thay đổi kích thước

  • vector: theo chèn / xóa [23.3.6.5/12]
  • deque: theo chèn / xóa [23.3.3.3/3]
  • list: theo chèn / xóa [23.3.5.3/1]
  • forward_list: theo chèn / xóa [23.3.4.5/25]
  • array: (không có)

Lưu ý 1

Trừ khi có quy định khác (rõ ràng hoặc bằng cách xác định hàm theo các hàm khác), việc gọi hàm thành viên vùng chứa hoặc chuyển một vùng chứa làm đối số cho hàm thư viện sẽ không làm mất hiệu lực các trình lặp trong hoặc thay đổi giá trị của các đối tượng trong vùng chứa đó . [23.2.1 / 11]

Lưu ý 2

không có chức năng hoán đổi () làm mất hiệu lực bất kỳ tham chiếu, con trỏ hoặc lặp nào đề cập đến các thành phần của các container được hoán đổi. [Lưu ý: Trình lặp end () không tham chiếu đến bất kỳ phần tử nào, vì vậy nó có thể bị vô hiệu . Ghi chú của người phụ nữ] [23.2.1 / 10]

Lưu ý 3

Khác với sự cảnh báo ở trên swap(), không rõ liệu các trình lặp "kết thúc" có tuân theo các quy tắc trên mỗi container được liệt kê ở trên hay không ; dù sao bạn cũng nên cho rằng chúng là như vậy.

Lưu ý 4

vectorvà tất cả các container liên kết không có thứ tự hỗ trợ reserve(n)đảm bảo rằng không có thay đổi kích thước tự động sẽ xảy ra ít nhất cho đến khi kích thước của container tăng lên n. Cần thận trọng với các container kết hợp không có thứ tự vì một đề xuất trong tương lai sẽ cho phép đặc tả hệ số tải tối thiểu, cho phép tái cấu trúc xảy ra insertsau khi đủ các erasehoạt động giảm kích thước container xuống dưới mức tối thiểu; bảo đảm nên được coi là có khả năng mất hiệu lực sau một erase.


Bên cạnh đó swap(), các quy tắc cho tính hợp lệ của trình lặp khi gán / sao chép chuyển nhượng là gì?
tạm biệt

@LightnessRacesinOrbit: Giống như chèn, xóa, thay đổi kích thước và hoán đổi, sao chép / di chuyển cũng là các chức năng thành viên của std :: vector, vì vậy tôi nghĩ bạn cũng có thể cung cấp các quy tắc về tính hợp lệ của trình vòng lặp cho chúng.
tạm biệt

@goodbyeera: Ý bạn là sao chép / di chuyển gán một yếu tố? Điều này sẽ không ảnh hưởng đến bất kỳ vòng lặp. Tại sao nó? Bạn đang nhấn Note 1 ở trên.
Các cuộc đua nhẹ nhàng trong quỹ đạo

1
Tôi nghĩ rằng tôi đã gây ra lỗi, bởi vì std::basic_stringdường như không được tính là một container và chắc chắn không phải là một container trong phần của tiêu chuẩn mà ghi chú áp dụng. Tuy nhiên, nơi nào nói SSO không được phép (tôi biết COW là)?
Ded repeatator

2
Các quy tắc này có giống nhau trong C ++ 14 không? C ++ 17 (theo như được biết đến bây giờ)?
einpoklum

40

Nó có lẽ là đáng nói thêm rằng một iterator chèn dưới mọi hình thức ( std::back_insert_iterator, std::front_insert_iterator, std::insert_iterator) đảm bảo sẽ vẫn có hiệu lực miễn là tất cả chèn được thực hiện thông qua iterator này và không có sự kiện iterator-hủy bỏ hiệu lực độc lập khác xảy ra.

Ví dụ, khi bạn đang thực hiện một loạt các thao tác chèn vào std::vectorbằng cách sử dụng std::insert_iterator, rất có thể các phần chèn này sẽ kích hoạt phân bổ lại vectơ, điều này sẽ làm mất hiệu lực tất cả các trình vòng lặp "trỏ" vào vectơ đó. Tuy nhiên, trình lặp chèn trong câu hỏi được đảm bảo vẫn còn hiệu lực, tức là bạn có thể tiếp tục một cách an toàn trình tự chèn. Không cần phải lo lắng về việc kích hoạt phân bổ lại vector.

Điều này, một lần nữa, chỉ áp dụng cho các phần chèn thêm được thực hiện thông qua chính trình lặp chèn. Nếu sự kiện vô hiệu hóa trình lặp được kích hoạt bởi một số hành động độc lập trên vùng chứa, thì trình lặp lặp chèn cũng trở nên vô hiệu theo các quy tắc chung.

Ví dụ: mã này

std::vector<int> v(10);
std::vector<int>::iterator it = v.begin() + 5;
std::insert_iterator<std::vector<int> > it_ins(v, it);

for (unsigned n = 20; n > 0; --n)
  *it_ins++ = rand();

được đảm bảo thực hiện một chuỗi chèn hợp lệ vào vectơ, ngay cả khi vectơ "quyết định" phân bổ lại ở đâu đó ở giữa quá trình này. Iterator itrõ ràng sẽ trở thành không hợp lệ, nhưng it_inssẽ tiếp tục duy trì hiệu lực.


22

Vì câu hỏi này thu hút rất nhiều phiếu bầu và loại trở thành Câu hỏi thường gặp, tôi đoán sẽ tốt hơn nếu viết một câu trả lời riêng để đề cập đến một sự khác biệt đáng kể giữa C ++ 03 và C ++ 11 về tác động của std::vectorhoạt động chèn của nó lên tính hợp lệ của các trình vòng lặp và các tham chiếu liên quan đến reserve()capacity(), mà câu trả lời được đánh giá cao nhất không thể nhận thấy.

C ++ 03:

Việc tái phân bổ làm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp tham chiếu đến các phần tử trong chuỗi. Đảm bảo rằng không có sự phân bổ lại diễn ra trong các lần chèn xảy ra sau lệnh gọi dự trữ () cho đến thời điểm chèn sẽ làm cho kích thước của vectơ lớn hơn kích thước được chỉ định trong lệnh gọi gần nhất để dự trữ () .

C ++ 11:

Việc tái phân bổ làm mất hiệu lực tất cả các tham chiếu, con trỏ và các trình vòng lặp tham chiếu đến các phần tử trong chuỗi. Nó được đảm bảo rằng không có sự phân bổ lại diễn ra trong các lần chèn xảy ra sau lệnh gọi dự trữ () cho đến thời điểm chèn sẽ làm cho kích thước của vectơ lớn hơn giá trị của dung lượng () .

Vì vậy, trong C ++ 03, nó không phải là " unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)" như được đề cập trong câu trả lời khác, thay vào đó, nó phải là " greater than the size specified in the most recent call to reserve()". Đây là một điều mà C ++ 03 khác với C ++ 11. Trong C ++ 03, một khi insert()làm cho kích thước của vectơ đạt đến giá trị được chỉ định trong reserve()cuộc gọi trước đó (có thể nhỏ hơn hiện tại capacity()reserve()có thể dẫn đến lớn capacity()hơn yêu cầu), bất kỳ lần tiếp theo nào insert()cũng có thể gây ra sự phân bổ lại và vô hiệu hóa tất cả các vòng lặp và tài liệu tham khảo. Trong C ++ 11, điều này sẽ không xảy ra và bạn luôn có thể tin tưởng capacity()để biết chắc chắn rằng việc tái phân bổ tiếp theo sẽ không diễn ra trước khi vượt qua kích thước capacity().

Tóm lại, nếu bạn đang làm việc với vectơ C ++ 03 và bạn muốn chắc chắn rằng việc tái phân bổ sẽ không xảy ra khi bạn thực hiện chèn, đó là giá trị của đối số bạn đã truyền trước đó reserve()mà bạn nên kiểm tra kích thước, không phải giá trị trả về của một cuộc gọi đến capacity(), nếu không bạn có thể cảm thấy ngạc nhiên về việc tái phân bổ " sớm ".


14
Tuy nhiên, tôi sẽ bắn bất kỳ trình biên dịch nào đã làm điều này với tôi, và không có bồi thẩm đoàn nào trong vùng đất sẽ kết án tôi.
Yakk - Adam Nevraumont

9
Tôi đã không "không chú ý" điều này; đó là một lỗi biên tập trong C ++ 03 đã được sửa trong C ++ 11. Không có trình biên dịch chính nào tận dụng lỗi.
Các cuộc đua nhẹ nhàng trong quỹ đạo

1
@Yakk Tôi nghĩ gcc đã vô hiệu hóa các trình vòng lặp trong các tình huống như vậy.
ShreevatsaR

2

Đây là một bảng tóm tắt tốt đẹp từ cppreference.com :

nhập mô tả hình ảnh ở đây

Ở đây, chèn đề cập đến bất kỳ phương thức nào thêm một hoặc nhiều phần tử vào vùng chứa và tẩy xóa đề cập đến bất kỳ phương thức nào loại bỏ một hoặc nhiều phần tử khỏi vùng chứa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.