C ++ 11 có cho phép vectơ <const T> không?


81

Yêu cầu vùng chứa đã thay đổi từ C ++ 03 thành C ++ 11. Trong khi C ++ 03 có các yêu cầu chung (ví dụ: khả năng tạo bản sao và khả năng gán cho vectơ), thì C ++ 11 xác định các yêu cầu chi tiết đối với mỗi hoạt động vùng chứa (phần 23.2).

Do đó, bạn có thể ví dụ: lưu trữ một kiểu có thể sao chép-xây dựng nhưng không thể gán được - chẳng hạn như cấu trúc có thành viên const - trong một vectơ miễn là bạn chỉ thực hiện một số hoạt động nhất định không yêu cầu gán (cấu trúc và push_backcác hoạt động đó ; insertkhông).

Điều tôi tự hỏi là: điều này có nghĩa là tiêu chuẩn bây giờ cho phép vector<const T>? Tôi không thấy lý do gì mà nó không nên - const T, cũng giống như cấu trúc có thành viên const, là một kiểu sao chép có thể xây dựng nhưng không thể gán được - nhưng tôi có thể đã bỏ sót điều gì đó.

(Một phần của điều khiến tôi nghĩ rằng tôi có thể đã bỏ lỡ điều gì đó, đó là thân cây gcc bị sập và cháy nếu bạn cố gắng khởi tạo vector<const T>, nhưng nó ổn với vector<T>nơi T có một thành viên const).

Câu trả lời:


54

Không, tôi tin rằng các yêu cầu của trình cấp phát nói rằng T có thể là "kiểu đối tượng không phải const, không phải tham chiếu".

Bạn sẽ không thể làm gì nhiều với một vector các đối tượng không đổi. Và const vector<T>dù sao a cũng sẽ gần giống nhau.


Nhiều năm sau, câu trả lời nhanh chóng và bẩn thỉu này dường như vẫn thu hút được nhiều bình luận và bình chọn. Không phải lúc nào cũng lên. :-)

Vì vậy, để thêm một số tài liệu tham khảo thích hợp:

Đối với tiêu chuẩn C ++ 03, mà tôi có trên giấy, Bảng 31 trong phần [lib.allocator.requirements] cho biết:

T, U any type

Không phải bất kỳ loại nào thực sự hoạt động.

Vì vậy, tiêu chuẩn tiếp theo, C ++ 11, đã nói trong một bản nháp gần đúng trong [secureator.requirements] và bây giờ là Bảng 27:

T, U, C any non-const, non-reference object type

mà rất gần với những gì tôi đã viết ở trên ban đầu từ trí nhớ. Đây cũng là những gì câu hỏi về.

Tuy nhiên, trong C ++ 14 ( bản nháp N4296 ) Bảng 27 hiện cho biết:

T, U, C any non-const object type

Có thể vì một tham chiếu có lẽ không phải là một kiểu đối tượng?

Và bây giờ trong C ++ 17 ( bản nháp N4659 ), Bảng 30 cho biết:

T, U, C any cv-unqualified object type (6.9)

Vì vậy, không chỉ được loại consttrừ, mà còn volatile. Có lẽ là tin cũ dù sao, và chỉ là một sự làm rõ.


Vui lòng xem thêm thông tin đầu tiên của Howard Hinnant , hiện ngay bên dưới.


42
Điểm mấu chốt: Chúng tôi không thiết kế các thùng chứa để giữ const T. Mặc dù tôi đã suy nghĩ về nó. Và chúng tôi đã thực sự tiến gần đến việc làm điều đó một cách tình cờ. Theo hiểu biết tốt nhất của tôi, điểm gắn bó hiện tại là cặp addresshàm thành viên được nạp chồng trong bộ cấp phát mặc định: Khi T là const, hai hàm nạp chồng này có cùng một chữ ký. Một cách dễ dàng để sửa lỗi này là chuyên môn hóa std::allocator<const T>và loại bỏ một trong những điểm quá tải.
Howard Hinnant

4
@ HighCommander4: Tôi không tích cực. Trên libc ++, tôi có thể tạo một vectơ (thậm chí là một vectơ không trống) với một bộ cấp phát hợp tác. Tôi không thể làm bất cứ điều gì khác (không phải const) với nó. Tôi không chắc liệu điều đó có phù hợp với định nghĩa của bạn về "tác phẩm" hay không. Tôi cũng không tích cực nếu tôi vô tình tận dụng một phần mở rộng. Để chắc chắn, tôi sẽ cần đầu tư nhiều thời gian hơn vào câu hỏi này. Tôi đã từng đầu tư như vậy trước đây, nhưng đó là cách đây vài năm, và rất nhiều thứ đã thay đổi trong thời gian ngắn. Nếu nó hoạt động, nó không phải do thiết kế của ủy ban.
Howard Hinnant

1
@Howard: Tôi không thể nghĩ ra bất kỳ trở ngại kỹ thuật nào để có thể làm được push_back. Nhưng nếu nó không được thiết kế cho phép, tốt hơn hết chúng ta không nên làm điều đó. Tôi chỉ là tò mò thôi.
HighCommander 4

7
Bộ nhớ đệm thường là một vùng chứa có thể thay đổi của các đối tượng bất biến và một vectơ được sắp xếp thường là một thay thế cho bản đồ, vì vậy tôi không đồng ý rằng một vectơ của các đối tượng const ít được sử dụng.
Chris Oldwood

9
Thật đáng tiếc. Tôi đã sử dụng std::vector<const T>chính xác vì nó rất giống với const std::vector<T>, nhưng không có ý nghĩa tiêu cực của cái sau đối với lớp đang nắm giữ nó. Trên thực tế, đó std::vector<const T>là CHÍNH XÁC những gì tôi cần về mặt ngữ nghĩa trong hầu hết các trường hợp tôi sử dụng vector. Bây giờ tôi phải giảm xuống const- cùng với độ tin cậy mà nó cung cấp.
Violet Giraffe

29

Cập nhật

Dưới câu trả lời được chấp nhận (và đúng), tôi đã nhận xét vào năm 2011:

Điểm mấu chốt: Chúng tôi không thiết kế các thùng chứa để chứa const T. Mặc dù tôi đã suy nghĩ về nó. Và chúng tôi đã thực sự tiến gần đến việc làm điều đó một cách tình cờ. Theo hiểu biết tốt nhất của tôi, điểm gắn bó hiện tại là cặp addresshàm thành viên bị quá tải trong bộ cấp phát mặc định: Khi nào Tthì consthai hàm quá tải này có cùng một chữ ký. Một cách dễ dàng để sửa lỗi này là chuyên môn hóa std::allocator<const T>và loại bỏ một trong những điểm quá tải.

Với bản nháp C ++ 17 sắp tới, tôi thấy rằng chúng tôi hiện đã được hợp pháp hóa vector<const T>và tôi cũng tin rằng chúng tôi đã vô tình làm điều đó . :-)

P0174R0 loại bỏ các addressquá tải khỏi std::allocator<T>. P0174R0 không đề cập đến việc hỗ trợ std::allocator<const T>như một phần lý do của nó.

Điều chỉnh

Trong các nhận xét bên dưới, TC lưu ý chính xác rằng addressquá tải không được dùng nữa , không bị loại bỏ. Lỗi của tôi. Các thành viên không dùng nữa sẽ không xuất hiện trong 20.10.9 nơi std::allocatorđịnh nghĩa, nhưng thay vào đó được đưa xuống phần D.9. Tôi đã sơ ý quét Chương D cho khả năng này khi tôi đăng nó.

Cảm ơn bạn TC về sự chỉnh sửa. Tôi đã dự tính xóa câu trả lời gây hiểu lầm này, nhưng có lẽ tốt nhất là nên để nó tiếp tục với sự chỉnh sửa này để có lẽ nó sẽ ngăn người khác đọc sai thông số kỹ thuật giống như cách tôi đã làm.


6
Điều đó khá thú vị! (Bây giờ chúng ta chỉ cần thực sự im lặng về nó, và để nó chuyển sang C ++ 17 mà không bị ai phát hiện :))
HighCommander 4

Không phải bảng yêu cầu trình phân bổ vẫn cấm nó hoàn toàn? Bất kể, P0174R2 (là bản sửa đổi được bình chọn) chỉ không dùng nữa, không loại bỏ address,.
TC

@TC: Bạn hoàn toàn đúng. Cảm ơn vì sự đúng đắn của bạn.
Howard Hinnant

Vì vậy, c ++ 2x cuối cùng sẽ cho phép vector<const T>:)
MM

1
Câu trả lời "Điểm mấu chốt: Chúng tôi không thiết kế vùng chứa để giữ const T.", giả định rằng mục tiêu là vùng chứa phải giữ "const T". Tuy nhiên, người ta có thể tranh luận rằng mục tiêu của người dùng là hạn chế các hoạt động trên vùng chứa - để ví dụ: 'back ()' trả về "const T &" - ​​bất kể vùng chứa chứa những gì.
Hans Olsson

8

Mặc dù chúng tôi đã có những câu trả lời rất tốt về vấn đề này, tôi quyết định đóng góp bằng một câu trả lời thiết thực hơn để chỉ ra những gì có thể và những gì không thể làm được.

Vì vậy, điều này không hoạt động:

vector<const T> vec; 

Chỉ cần đọc các câu trả lời khác để hiểu tại sao. Và, như bạn có thể đoán, điều này cũng sẽ không hoạt động:

vector<const shared_ptr<T>> vec;

Tkhông còn nữa const, nhưng vectorđang giữ shared_ptrs, không phải Ts.

Mặt khác, điều này không làm việc:

vector<const T *> vec;
vector<T const *> vec;  // the same as above

Nhưng trong trường hợp này, const là đối tượng được trỏ tới, không phải chính con trỏ (là thứ mà vector lưu trữ). Điều này sẽ tương đương với:

vector<shared_ptr<const T>> vec;

Cái nào tốt.

Nhưng nếu chúng ta đặt constở cuối biểu thức, nó sẽ biến con trỏ thành a const, do đó, phần sau sẽ không biên dịch:

vector<T * const> vec;

Hơi khó hiểu, tôi đồng ý, nhưng bạn sẽ quen.


4

Bổ sung cho các câu trả lời khác, một cách tiếp cận khác là sử dụng:

vector<unique_ptr<const T>> vec;

Nếu đó là trường hợp bạn chỉ muốn thực thi vec có quyền sở hữu các mục của nó. Hoặc nếu bạn muốn một động thái chuyển các mục vào vecvà một lúc nào đó chuyển chúng ra ngoài.

Như đã chỉ ra, constngữ nghĩa của con trỏ có thể khó hiểu, nhưng shared_ptrunique_ptrkhông. const unique_ptr<T>là một con trỏ const và unique_ptr<const T>là một con trỏ const như bạn mong đợi.

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.