2013-07-12 49 views
10

Mục 9.6/3 trong C++ 11 rõ ràng là bất thường: "Một tham chiếu không const sẽ không bị ràng buộc vào một trường bit." Động lực đằng sau lệnh cấm này là gì?Tại sao các tham chiếu không phải const tham chiếu đến bitfield bị cấm?

Tôi hiểu rằng không thể trực tiếp ràng buộc tham chiếu đến bitfield. Nhưng nếu tôi tuyên bố điều gì đó như thế này,

struct IPv4Header { 
    std::uint32_t version:4,   // assumes the IPv4 Wikipedia entry is correct 
       IHL:4, 
       DSCP:6, 
       ECN:2, 
       totalLength:16; 
}; 

tại sao tôi không thể nói điều này?

IPv4Header h; 

auto& ecn = h.ECN; 

tôi mong đợi các mã cơ bản để thực sự liên kết với toàn bộ std::uint32_t có chứa các bit Tôi quan tâm đến, và tôi mong đợi đọc và ghi các hoạt động để tạo ra mã để làm mặt nạ thích hợp. Kết quả có thể lớn và chậm, nhưng có vẻ như với tôi rằng nó sẽ hoạt động. Đây sẽ là phù hợp với đường tiêu chuẩn nói rằng tài liệu tham khảo để const bitfields công việc (một lần nữa từ 9,6/3):

Nếu initializer cho một tham chiếu kiểu const T & là một giá trị trái nó liên quan tới một chút -field, tham chiếu được ràng buộc với một tạm thời được khởi tạo để giữ giá trị của trường bit; tham chiếu không bị ràng buộc trực tiếp vào trường bit.

Điều này gợi ý rằng việc ghi vào bitfield là vấn đề, nhưng tôi không thấy nó là gì. Tôi đã xem xét khả năng mặt nạ cần thiết có thể giới thiệu các chủng tộc trong mã đa luồng, nhưng, trên 1,7/3, bitfield liền kề có chiều rộng khác 0 được coi là một đối tượng duy nhất cho mục đích đa luồng. Trong ví dụ trên, tất cả các bitfield trong một đối tượng IPv4Header sẽ được coi là một đối tượng duy nhất, vì vậy mã đa luồng cố gắng sửa đổi một trường trong khi đọc các trường khác theo định nghĩa, đã được cải thiện.

Tôi rõ ràng thiếu điều gì đó. Nó là gì?

Trả lời

7

Tham chiếu không phải const không thể bị ràng buộc với các trường bit cho cùng một con trỏ lý do không thể trỏ đến các trường bit.

Mặc dù không được chỉ định xem tham chiếu có lưu trữ hay không, rõ ràng là trong trường hợp không tầm thường chúng được triển khai dưới dạng con trỏ trong ngụy trang, và việc thực hiện tham chiếu này là "dự định" của tác giả ngôn ngữ. Và cũng giống như con trỏ, tài liệu tham khảo phải trỏ đến một đơn vị lưu trữ địa chỉ. Không thể liên kết tham chiếu không const với một đơn vị lưu trữ không thể định địa chỉ. Vì các tham chiếu không const yêu cầu ràng buộc trực tiếp, một tham chiếu không phải const không thể bị ràng buộc vào một trường bit.Cách duy nhất để tạo ra một con trỏ/tham chiếu có thể trỏ đến các trường bit sẽ là thực hiện một số loại "siêu con trỏ" ngoài địa chỉ thực trong bộ nhớ cũng sẽ chứa một số loại bit-offset và bit thông tin về độ rộng, để cho biết mã viết mà bit cần sửa đổi. Lưu ý rằng thông tin bổ sung này sẽ phải có mặt trong tất cả các kiểu con trỏ dữ liệu, vì không có kiểu như vậy trong C++ là "pointer/reference to bit-field". Điều này về cơ bản là tương đương với việc triển khai một mô hình địa chỉ lưu trữ cấp cao hơn, khá tách biệt với mô hình địa chỉ được cung cấp bởi nền tảng hệ điều hành/phần cứng cơ bản. Ngôn ngữ C++ không bao giờ có ý định yêu cầu loại trừu tượng đó từ nền tảng cơ sở ra khỏi những cân nhắc hiệu quả thuần túy.

Một cách tiếp cận khả thi là giới thiệu một danh mục con trỏ/tham chiếu riêng biệt như "con trỏ/tham chiếu đến trường bit", có cấu trúc bên trong phức tạp hơn con trỏ/tham chiếu dữ liệu thông thường. Các kiểu như vậy sẽ được chuyển đổi từ các kiểu dữ liệu/con trỏ thông thường, nhưng không phải là cách khác. Nhưng nó không có vẻ xứng đáng.

Trong trường hợp thực tế, khi tôi phải xử lý dữ liệu được đóng gói thành bit và chuỗi bit, tôi thường thích thực hiện các trường bit theo cách thủ công và tránh các trường bit cấp ngôn ngữ. Tên của trường bit là một thực thể biên dịch-thời gian không có khả năng lựa chọn thời gian chạy của bất kỳ loại nào. Khi lựa chọn thời gian chạy là cần thiết, cách tiếp cận tốt hơn là khai báo một trường dữ liệu thông thường uint32_t và quản lý các bit và nhóm bit riêng biệt bên trong nó theo cách thủ công. Việc lựa chọn thời gian chạy của trường bit "thủ công" như vậy được thực hiện dễ dàng thông qua các mặt nạ và sự dịch chuyển (cả hai có thể là các giá trị thời gian chạy). Về cơ bản, điều này là gần với việc thực hiện thủ công các "superpointers" nói trên.

+0

Tôi đánh dấu đây là câu trả lời, bởi vì nó làm cho rõ ràng những gì tôi nghĩ là đối số chính: rằng nếu một tham chiếu đến từ giữ một bitfield đã làm việc theo cách tôi phác thảo, sẽ có một nhu cầu bổ sung thông tin liên quan đến bù đắp của bitfield vào từ, và đó là không thực tế thực hiện được cho các mô hình tham khảo-là-con trỏ-dưới-mui xe mà C++ sử dụng. – KnowItAllWannabe

9

Bạn không thể tham chiếu không const vào bitfield vì lý do tương tự bạn không thể lấy địa chỉ của nó bằng &: địa chỉ thực tế của nó không nhất thiết được liên kết với char. trong C++ máy trừu tượng. Bạn có thể tham chiếu const cho nó vì trình biên dịch miễn phí cho sao chép giá trị, vì nó sẽ không bị đột biến.

Cân nhắc vấn đề biên dịch riêng biệt. Chức năng chụp const uint32_t& cần sử dụng cùng một mã để hoạt động trên bất kỳ const uint32_t& nào. Nếu hành vi viết khác nhau là bắt buộc đối với giá trị thông thường và giá trị bitfield thì loại đó không mã hóa đủ thông tin để chức năng hoạt động chính xác trên cả hai.

+0

Điều này không thực sự trả lời câu hỏi, IMO. Tại sao không thể tham chiếu không phải 'const' liên kết với từ chứa bitfield, sau đó, trên ghi, thực hiện mặt nạ cần thiết để chỉ sửa đổi các bit trong bitfield? Đây có lẽ là điều xảy ra khi bitfield được sửa đổi trực tiếp, phải không? – KnowItAllWannabe

+1

Bit cuối cùng là sai. Tham chiếu const ngụ ý không có gì về giá trị đang được hoặc không bị đột biến. Nó chỉ ngăn chặn đột biến thông qua tham chiếu * that *. –

+1

@AndreyT Điều đó vẫn không làm cho từ ngữ đó chính xác hơn. Trình biên dịch không phải là miễn phí để sao chép nó bởi vì nó sẽ không bị đột biến. Không có nguyên nhân ở đây. Trình biên dịch là miễn phí để sao chép nó * theo nghị định *. Nó không phải vì sự biến đổi của bitfield, bởi vì nó được viết như vậy. Trên thực tế, nó không thực sự * miễn phí * để sao chép nó, nó * cần * để sao chép nó. –

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