2013-09-03 33 views
5

Theo như tôi biết trong C++ cấu trúc/lớp thành viên với cùng một điều khiển truy cập được lưu trữ trong bộ nhớ theo thứ tự khai báo. Là ví dụ tiếp theo mc nên được lưu trữ một sau khi khác:Thành viên có thể thay đổi không cho phép tối ưu hóa const cho các thành viên không thể thay đổi không?

#include <cstdlib> 
#include <iostream> 

struct X 
{ 
    mutable int m; 
    int   c; 
}; 

const X cx = {0, 1}; 

int main() 
{ 
    X& x = const_cast<X&>(cx); 

    x.m = rand(); 
    x.c = rand(); 

    std::cout<<x.m<<" "<<x.c; 
} 

Trong ví dụ này, chương trình chạy và in 2 số ngẫu nhiên. Nếu tôi xóa mutable lỗi này sẽ bị treo vì cx được lưu trữ trong bộ nhớ được bảo vệ chỉ đọc.

Điều này làm tôi ngạc nhiên - không một thành viên mutable vô hiệu hóa const tối ưu hóa cho toàn bộ struct (bằng cách nào đó khiến tất cả thành viên mutable)?

Có thể lưu trữ các bộ phận của struct trong bộ nhớ chỉ đọc và các bộ phận khác trên bộ nhớ không đọc và tôn trọng bố cục bộ nhớ tiêu chuẩn C++ không?

Điều này đã được thử nghiệm bằng Visual Studio 2010 trên Windows 7 và GCC 4.7.2 trên Ubuntu.

Trả lời

4

Để giải thích tại sao trình biên dịch phải làm "tất cả hoặc không có gì" khi nói đến nơi lưu trữ struct: Trong hầu hết các bộ xử lý, trang bộ nhớ là 4KB (một số có 8KB trang). Đó là mức độ chi tiết của khối bộ nhớ "chỉ đọc" so với "đọc/ghi". Vì vậy, bạn không thể có một số nguyên 4 byte trong bộ nhớ chỉ đọc, và sau đó là số nguyên 4 byte tiếp theo trong bộ nhớ đọc-ghi (trừ khi chúng chính xác nằm trong ranh giới bộ nhớ 4KB - nhưng điều đó chắc chắn sẽ làm cho việc sử dụng khá lãng phí bộ nhớ nếu bạn có một mảng của 3000 người trong số họ, chiếm 12MB).

Lưu ý rằng đây không phải là "tối ưu hóa". Bộ nhớ chỉ đọc không nhanh hơn bộ nhớ ghi đọc. Đó là sự bảo vệ chống lại người dùng ngớ ngẩn với const và ghi vào dữ liệu mà họ không nên ghi. Ngoài ra nếu bạn thêm một hàm tạo "làm một cái gì đó" vào struct của bạn, nó rất có thể sẽ lưu trữ cấu trúc trong bộ nhớ đọc-ghi, bởi vì nó khá khó khăn cho trình biên dịch để tạo mã để chuyển đổi chỉ đọc và tắt trong thời gian chạy.

+0

Tôi thêm X() constructor mà inits m và c và cx không có trong bộ nhớ chỉ đọc như trước đây. Cái nhìn rất thú vị, cảm ơn! – Felics

1

Từ khóa "const" là nhãn cho nhóm lập trình viên như "riêng tư" và "công khai" chứ không phải chỉ thị trình biên dịch hoặc gợi ý trình biên dịch. Một trình biên dịch có thể sử dụng nó để tối ưu hóa nhưng không cần. Trình biên dịch chỉ kiểm soát việc lạm dụng và ngăn chặn nó. Vì vậy, hành vi bạn thấy là hoàn toàn ok. Và không, không thể là các phần của một cá thể struct hoặc cá thể lớp tồn tại trong các vùng bộ nhớ khác nhau (không tính ánh xạ). Bởi vì quyết định đó sẽ tác động đến việc sử dụng cấu trúc và phải được cho phép bởi lập trình viên.

+0

"từ khóa" const "là nhãn hiệu cho nhóm lập trình viên" - Tôi e rằng, trong trường hợp này các thành viên của nhóm này có thể có những ý kiến ​​hơi khác về ý nghĩa của nhãn này. – SChepurin

+0

Tôi có nghĩa là lời giải thích tốt sẽ là - "Vòng loại const là một hướng dẫn để trình biên dịch từ chối mã cố gắng sửa đổi đối tượng đó trực tiếp, cố gắng sửa đổi đối tượng gián tiếp ... kết quả trong hành vi không xác định, có nghĩa là bất kỳ kết quả nào có thể . " (http://stackoverflow.com/questions/4275504/deep-analysis-of-const-qualifier-in-c) – SChepurin

+0

Bạn nói đúng. Câu trả lời của tôi đã được viết vội vàng. Tuy nhiên, theo ý kiến ​​của tôi, con người có thể đọc được nhiều hơn. Và vâng, làm việc trong các nhóm khác nhau trong những năm qua, tôi luôn ngạc nhiên khi mọi người cố gắng lừa trình biên dịch và mong đợi làm việc theo cách thích hợp. –

5

Các cuộc đàm phán tiêu chuẩn về mutable thành viên ở nhiều nơi. Tôi trích dẫn dưới ba phần của tiêu chuẩn giải thích rằng bạn chỉ có thể sửa đổi các thành viên mutable của đối tượng const. Nếu không, nó là Hành vi không xác định.

3.9.3 CV-vòng loại [basic.type.qualifier]

Một đối tượng const là một đối tượng kiểu const T hoặc một subobject không thể thay đổi của một đối tượng như vậy.

[...]

7.1.1 specifiers lớp lưu trữ [dcl.stc]

Các mutable specifier trên một thành viên lớp dữ liệu làm vô hiệu một specifier const áp dụng cho các đối tượng lớp chứa và cho phép sửa đổi thành viên lớp mutable mặc dù phần còn lại của đối tượng là const.

[...]

7.1.6.1 Các cv-vòng loại [dcl.type.cv]

Trừ rằng bất kỳ thành viên lớp tuyên bố mutable (7.1.1) có thể được sửa đổi , mọi nỗ lực sửa đổi đối tượng const trong suốt thời gian tồn tại của nó (3,8) dẫn đến hành vi không xác định.


Có thể lưu trữ các bộ phận của một struct trong bộ nhớ chỉ đọc và các bộ phận khác trên không chỉ đọc bộ nhớ và tôn trọng C++ bố trí bộ nhớ tiêu chuẩn?

Không, không thể lưu trữ các bộ phận của struct (hoặc class) vào một vùng bộ nhớ khác với phần còn lại của đối tượng.

+0

Vì vậy, 'x.c = rand();' trong 'main' kích hoạt UB trong cả hai trường hợp, đúng không? – Hulk

+0

@Hulk Có, từ khóa 'mutable' trên' m' không thay đổi bất cứ điều gì cho 'c'. Xem bài đăng này: http://stackoverflow.com/a/583150/1394283. Nó giải thích tốt phần cuối cùng của báo giá chuẩn I. –

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