2013-10-23 15 views
10

Tôi tự hỏi, chính xác bảo đảm an toàn ngoại lệ cho std::vector::insert là gì? Tôi quan tâm đến cả hai đối số đơn và phạm vi quá tải của hàm này.Bảo đảm an toàn ngoại lệ của vector :: chèn là gì?

+2

Điều này phụ thuộc rất nhiều vào loại được lưu trữ trong vùng chứa –

+0

@David: Bạn chính xác. Tôi quan tâm đến trường hợp nó không có động thái không rõ ràng - ví dụ: chỉ ném bản sao. – Puppy

Trả lời

2

Việc bảo lãnh chính xác được đưa ra trong C++ 11 23.3.6.5:

Nếu một ngoại lệ được ném khác hơn là bởi các nhà xây dựng sao chép, di chuyển nhà xây dựng, nhà điều hành chuyển nhượng, hoặc di chuyển điều hành giao T hoặc bằng bất kỳ hoạt động InputIterator nào cũng không có hiệu ứng. Nếu một ngoại lệ được ném bởi hàm tạo di chuyển của một số không CopyInsertableT, thì các hiệu ứng sẽ không được chỉ định.

+0

Điều này có nghĩa gì với 'không có hiệu ứng'? Điều gì sẽ xảy ra với các phần tử đã được gán trong vectơ? – RedX

+1

@RedX: Điều đó có nghĩa là không có hiệu ứng; mọi thứ được phục hồi về trạng thái ban đầu, như thể không có gì xảy ra. Nếu đã có các phần tử đã được gán, thì ngoại lệ phải được ném bởi "hàm tạo bản sao, di chuyển hàm tạo, toán tử gán, hoặc di chuyển toán tử gán của' T' hoặc bởi bất kỳ thao tác 'InputIterator' nào", trong trường hợp đó không có sự bảo đảm như vậy . –

+2

Vì vậy, điều này ngụ ý đảm bảo cơ bản cho nếu các nhà xây dựng bản sao của T ném? – Puppy

1

Nếu phương pháp insert chèn một phần tử đơn lẻ vào cuối danh sách và không yêu cầu bất kỳ bộ nhớ nào được cấp phát, hãy cung cấp bảo đảm ngoại lệ mạnh.

Nếu nó phải thêm nhiều hơn một phần tử hoặc phải cấp phát bộ nhớ, nó cung cấp bảo đảm ngoại lệ cơ bản. Boost có mô tả tốt về bảo đảm ngoại lệ.

Đảm bảo cơ bản: rằng các bất biến của thành phần được giữ nguyên và không có tài nguyên nào bị rò rỉ. Đảm bảo mạnh mẽ: rằng hoạt động đã hoàn tất thành công hoặc ném một ngoại lệ, để trạng thái chương trình chính xác như trước khi bắt đầu hoạt động. Đảm bảo không đảm bảo: hoạt động sẽ không loại trừ ngoại lệ.

Điều này có nghĩa là sau một ngoại lệ, bạn biết rằng vector sẽ có thể sử dụng được, nhưng có thể không có tất cả dữ liệu bạn đã chèn vào. Tất cả các đối tượng đã được chèn thành công sẽ được xây dựng hoàn chỉnh.

2

Nói chung, hình thức-yếu tố duy nhất của insert có một bảo đảm ngoại lệ mạnh mẽ cho bất kỳ container theo [container.requirements.general]/10, nhưng vector::insert là một ngoại lệ cho quy tắc này:

[vector .modifiers]/1 áp dụng cho vector::insert; InputIterator ở đây đề cập đến tình trạng quá tải của insert chèn một phạm vi.

Nếu một ngoại lệ được ném khác hơn là bởi các nhà xây dựng sao chép, di chuyển nhà xây dựng, nhà điều hành chuyển nhượng, hoặc di chuyển điều hành giao T hoặc bởi bất kỳ hoạt động InputIterator không có tác dụng. Nếu một ngoại lệ được ném bởi hàm tạo-di chuyển của một không CopyInsertableT, các hiệu ứng không được chỉ định.


vector là nơi chứa cấp phát-aware, có nghĩa là nó sử dụng một cấp phát cho phân bổ bộ nhớ xây dựng các yếu tố của nó [container.requirements.general]/3

Đối các thành phần bị ảnh hưởng bởi điều này mà tuyên bố một allocator_type, các đối tượng được lưu trữ trong các thành phần này phải được xây dựng bằng cách sử dụng chức năng allocator_traits<allocator_type>::construct và bị phá hủy bằng chức năng allocator_traits<allocator_type>::destroy. Các hàm này chỉ được gọi cho loại phần tử của vùng chứa, không phải cho các loại nội bộ được vùng chứa sử dụng.

Tôi nghĩ rằng điều này ngụ ý rằng các đối tượng cục bộ, không phải là thành phần của vùng chứa, có thể được tạo mà không sử dụng trình cấp phát (ví dụ: sao chép và trao đổi). Nếu không, các yêu cầu trên các ctors của kiểu giá trị sẽ là vô nghĩa; chức năng construct của người cấp phát có thể có các bảo đảm ngoại lệ khác với hàm ctor của loại giá trị.


CopyInsertable được quy định tại [container.requirements.general]/13 bằng cách yêu cầu

allocator_traits<A>::construct(m, p, v); 

là tốt được hình thành; nơi A là loại cấp phát, m là loại A, p là một con trỏ đến T, v là một biểu hiện của loại (const) T, và T là kiểu giá trị của container. Đây là một xây dựng tại chỗ từ một đối số (bản sao hoặc di chuyển-xây dựng).

Tương tự, MoveConstructible được chỉ định, nhưng v là (luôn luôn) giá trị của loại T. EmplaceConstructible theo cùng một biểu mẫu cho số không hoặc nhiều đối số thay vì v.

Chức năng insert cho các vùng chứa chuỗi áp đặt các yêu cầu khác nhau về loại giá trị cho các dạng khác nhau của nó [sequence.reqmts]; ở đây bao gồm cả yêu cầu bổ sung cho vector:

  • cho một đối số duy nhất đó là một vế trái của loại (const) T và cho chèn hình thức N bản sao của, T sẽ CopyInsertableCopyAssignable
  • cho một đơn Lập luận đó là một rvalue loại T, T sẽ MoveInsertableMoveAssignable
  • đối với hình thức phạm vi, T sẽ EmplaceConstructible từ các biến lặp không quan tâm (*); thêm vào đó, MoveInsertableMoveAssignable nếu lặp của dãy núi này có lặp về phía trước

(*) Lưu ý: EmplaceConstructible chỉ từ lặp dereferenced là không đủ nếu container phải được thay đổi kích cỡ cho chèn (và, ví dụ như *i cho một trình lặp như vậy không thuộc loại giá trị). Có thể đặc điểm kỹ thuật yêu cầu biểu mẫu phạm vi để kế thừa các yêu cầu của biểu mẫu phần tử đơn, tức là MoveAssignable hoặc CopyAssignable.

Nhận xét bên: Biểu mẫu phạm vi insert yêu cầu hai trình vòng lặp không trỏ vào vùng chứa mà chúng được chèn vào.


tôi giải thích các thông số kỹ thuật ngoại lệ như sau:

Báo cáo bổ sung về CopyInsertable trong đặc tả ngoại lệ của vector::insert lẽ phân biệt giữa bảo lãnh cơ bản và không có bảo đảm: Các dtor của một container thường được yêu cầu để gọi các dtor của tất cả các yếu tố và deallocate tất cả bộ nhớ (trong các yêu cầu container chung). Đó là, trừ khi hành vi không xác định/không xác định, bảo đảm cơ bản giữ.

Tại sao có yêu cầu kết hợp CopyInsertable và di chuyển-ctor (thay vì allocator::construct với giá trị), tôi không biết. Các di chuyển-ctor chỉ được sử dụng trực tiếp cho các đối tượng không phải là yếu tố của container (gián tiếp có thể thông qua allocator::construct).

Các nhận xét khác về "không có hiệu ứng" (-> đảm bảo mạnh) là không áp dụng cho các hoạt động cấp phát (construct). Các hoạt động cấp phát rõ ràng không phải là không nhận diện. Vì bạn có thể cung cấp một trình cấp phát không mặc định không sử dụng bản sao và di chuyển-ctor của loại giá trị cho construct, insert phải cung cấp bảo đảm ngoại lệ mạnh ngay cả đối với các hoạt động cấp phát construct. Ví dụ, nếu số phân bổ construct của người cấp phát không phải là ngoại lệ, trong khi thay đổi kích thước, các phần tử không thể di chuyển được xây dựng nhưng phải được sao chép.

Chuyển nhượng và chuyển nhượng phải không được chấp nhận đối với đảm bảo mạnh vì các yếu tố có thể cần được dịch chuyển xung quanh cho insert; copy- và move-ctor có thể cần phải không được chấp nhận cho sự bảo đảm mạnh mẽ vì các đối tượng địa phương được tạo ra trong thuật toán.

+0

Về nhận xét bên của bạn: bạn sẽ làm gì nếu bạn * muốn * chèn một số thành phần của vùng chứa bên trong chính nó? – Mehrdad

+0

@Mehrdad Sử dụng biểu mẫu một phần tử? Ít nhất, [bắt buộc phải làm việc] (http://stackoverflow.com/q/18788780/420683). – dyp

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