2013-07-30 24 views
10

Đưa những từ here (đó là khá cũ):Có sai không nếu loại phần tử thùng chứa chuẩn và std :: loại cấp phát khác nhau?

Nó cũng quan trọng là loại sử dụng cho tham số cấp phát mẫu và loại sử dụng như các loại nguyên tố trong một container tiêu chuẩn đồng ý. Ví dụ:

std::list<int, std::allocator<long> >     // Wrong! 

sẽ không hoạt động.

Câu hỏi

là tuyên bố trên đúng (hoặc là nó bao giờ đúng)? Bất kỳ thử nghiệm nào tôi đã thực hiện có vẻ ổn nhưng không có vấn đề gì tôi đặt cho T trong std::allocator. Ví dụ: std::vector<int, std::allocator<std::string>> được biên soạn và hoạt động tốt để đẩy lùi và xóa các phần tử, v.v. (Từ những gì tôi hiểu là std::allocator<std::string>::rebind<int>::other là phép thuật làm cho công việc này).

+0

kiểm tra kích thước của cấu trúc dữ liệu khi bạn sử dụng các loại khác nhau – aaronman

+0

@aaronman: Kích thước của 'std :: list' có thể hoặc không khác nhau khi các loại dữ liệu khác nhau được sử dụng cho loại hoặc cấp phát. Điều đó sẽ không thực sự cho bạn biết bất cứ điều gì –

+0

@ DavidRodríguez-dribeas trong trường hợp danh sách bạn sẽ kiểm tra kích thước của một nút nếu điều đó thậm chí có thể là – aaronman

Trả lời

6

CHỈNH SỬA: Trong [containers.requirements.general], yêu cầu vùng chứa nhận biết của Allocator cho biết rằng allocator_type::value_type giống với Container::value_type.

Vì vậy, nó bị bệnh hình thành để vượt qua trong một loại phân bổ với một khác nhau value_type, mặc dù ít nhất một thực hiện chỉ đơn giản là sử dụng allocator_traits<...>::rebind<value_type> để có được phân bổ chính xác.

+2

N3485 có trong container.requirements.general, Bảng 99 "Yêu cầu vùng chứa nhận biết Allocator" nói rằng 'allocator_type :: value_type' phải giống với' X :: value_type'. Điều này có khác biệt trong C++ 11 đúng không? – aschepler

+0

@aschepler, ah, điểm tốt. Tôi đã bỏ lỡ cái bàn đó. Điều đó ngụ ý rằng nó bị bệnh hình thành để sử dụng một loại phân bổ khác nhau, mặc dù hầu hết các triển khai hỗ trợ nó. – MSN

+0

Cảm ơn bạn đã trả lời. Tôi đã tìm thấy [câu hỏi SO này] (http://stackoverflow.com/questions/15224988/custom-allocator-for-stdvectorchar-is-ignored), do đó, có vẻ như libstdC++ đã được 'rebind'ing luôn luôn và tôi không biết về triển khai không thực hiện điều đó. Tuy nhiên, điều thú vị là tất cả họ đều vi phạm tiêu chuẩn. –

7

Tôi đang thêm câu trả lời ở đây để làm rõ sự khác biệt giữa hành vi không đúng định dạng và không xác định.

[intro.compliance]/p1:

Các bộ quy tắc có thể chẩn đoán bao gồm tất cả các cú pháp và ngữ nghĩa quy tắc trong tiêu chuẩn quốc tế này, ngoại trừ đối với những quy tắc chứa một ký hiệu rõ ràng rằng “không chẩn đoán được yêu cầu ”hoặc là mô tả là dẫn đến‘hành vi không xác định’

[defns.ill.formed]:.

chương trình mà không được cũng được hình thành

[defns.well.formed]

chương trình

C++ được xây dựng theo các quy tắc cú pháp, có thể chẩn đoán quy tắc ngữ nghĩa, và One Definition Rule (3.2) .

Bằng tiếng Anh: chương trình không đúng định dạng sẽ có chẩn đoán liên quan đến nó. Hành vi không xác định có thể làm bất cứ điều gì:

  1. Nó có thể biên dịch và thực hiện như bạn dự định.
  2. Nó có thể đưa ra chẩn đoán.
  3. Nó có thể xóa mã bạn đã viết.
  4. Nó có thể định dạng lại đĩa gần nhất.

(tất cả nhưng thứ 4 thường xuyên xảy ra trong thực tế)

hành vi Không xác định là rất xấu, và IMHO, C và C++ tiêu chuẩn áp dụng đặc điểm kỹ thuật mà nhiều quá tự do.

Về mặt kỹ thuật, vi phạm một mệnh đề Yêu cầu dẫn đến hành vi không xác định.

[res.on.required]/p1:

Vi phạm các điều kiện tiên quyết quy định trong một chức năng của Yêu cầu: kết quả đoạn trong hành vi undefined trừ của chức năng Ném: đoạn quy định cụ thể ném một ngoại lệ khi điều kiện tiên quyết bị vi phạm .

Theo ghi nhận của MSN, allocator_type::value_type sẽ được giống như container::value_type như đã nêu trong Bảng 99 - cấp phát-aware chứa yêu cầu.

allocator_type A  Requires: allocator_type::value_type 
            is the same as X::value_type. 

(X biểu thị một lớp container cấp phát-aware với một value_type của T sử dụng cấp phát loại A)

Vì vậy, một sự vi phạm như:

std::list<int, std::allocator<long> > 

là hành vi không xác định. Vì vậy, nó:

  1. có thể biên dịch và thực hiện như bạn dự định.
  2. có thể đưa ra chẩn đoán.
  3. có thể xóa mã bạn đã viết.
  4. có thể định dạng lại đĩa gần nhất.

Chỉ rất gần đây (trong vòng tuần tôi viết thư này), libC++ (http://libcxx.llvm.org) đã bắt đầu chẩn đoán xác định hành vi này với static_assert để bạn có được những tin tức xấu càng sớm càng tốt.

Chúng tôi quyết định đi theo hướng này, thay vì cho phép hành vi vì các vùng chứa không được thiết lập để cho phép chuyển đổi giữa các loại có liên quan chặt chẽ. Ví dụ:

std::list<int, std::allocator<long>> list1; 
std::list<int>      list2 = list1; // is specified to not work 

I.e. nếu bạn bắt đầu xử lý list1list2 là các loại tương đương vì std::allocator nhận được rebind 'd anyway, bạn sẽ thấy thất vọng khi bạn khám phá hai danh sách thực sự là các loại khác nhau và không được thiết kế để tương thích. Vì vậy, nó thực sự là tốt nhất để có được những tin tức xấu càng sớm càng tốt, thay vì tìm ra 2 tháng, hoặc 2 năm sau đó, khi bạn cố gắng sử dụng chúng như các loại tương đương.

Có thể tiêu chuẩn tương lai sẽ xử lý các loại tương đương list1list2. Đó là chủ yếu về mặt kỹ thuật có thể (std::is_same có thể sẽ không hoạt động). Nhưng không có đề xuất nào mà tôi đã nghe theo hướng này. Hướng này dường như không có khả năng đối với tôi. Và với static_assert, lỗi có thể dễ dàng chẩn đoán được.Thay vào đó, tôi muốn thấy việc di chuyển tiêu chuẩn theo hướng làm cho mã này không đúng định dạng thay vì không xác định. Phần khó nhất trong việc làm như vậy sẽ là từ-smithing tiêu chuẩn, và không phải trong std :: lib thực hiện.

+0

Nếu 'std :: list' là một' sử dụng 'bí danh cho một loại thực, nó có thể làm' rebind' trước khi trở thành một loại "thực". Nhưng tôi nghĩ rằng 'sử dụng' bí danh thất bại trong một số tình huống phù hợp với mô hình, do đó, sẽ không làm việc, bah. – Yakk

+0

"Trong tiếng Anh: một chương trình không đúng hình thức sẽ có một chẩn đoán liên kết với nó." Ngay cả một chương trình hình thành không đúng có thể không đưa ra chẩn đoán vì các vi phạm ODR không phải được chẩn đoán. – bames53

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