2010-01-05 80 views
13

Tôi đang cố gắng thay đổi giá trị của một biến được định nghĩa là int const như dưới đây.thay đổi giá trị của biến const trong C++

const int w = 10; 
int* wp = const_cast <int*> (&w); 
*wp = 20; 

Giá trị của w không thay đổi và là 10 ngay cả sau khi gán, mặc dù nó hiển thị như thể cả w và wp đang trỏ đến cùng một vị trí bộ nhớ. Nhưng tôi có thể thay đổi giá trị của w, nếu định nghĩa như sau trong khi tuyên bố

int i = 10; 
const int w = i; 

Nếu tôi thay đổi tuyên bố của tôi để làm cho nó const như trong

const int i = 10; 

Giá trị của w doesn không thay đổi.

Trong trường hợp đầu tiên, làm thế nào đến giá trị của w không thay đổi, mặc dù w và wp điểm đến vị trí nhớ cùng [đó là ấn tượng của tôi, tôi nhận được khi tôi in địa chỉ của họ]

gì khác biệt nó đến trình biên dịch mà nó xử lý cả hai trường hợp khác nhau?

Có cách nào để đảm bảo rằng w không bị mất độ chói, không phân biệt cách nó được xác định?

+11

Nếu một đối tượng ban đầu được tạo thành 'const', thì bạn không thể (không nên)' const_cast' nó thành một 'nonst'; đó là hành vi không xác định. Nếu một đối tượng ban đầu được tạo ra không phải là 'const', bạn có thể 'const_cast' qua lại như bạn muốn. –

+5

Trên một số triển khai, việc ghi vào đối tượng 'const' có thể làm hỏng chương trình của bạn, nếu nội dung của đối tượng nằm trong phần chỉ đọc (ví dụ' .ata'' trái ngược với '.data', trong đó dữ liệu không phải' ' ngồi). –

+6

Không ai dường như đã hỏi câu hỏi rõ ràng - nếu bạn muốn thay đổi giá trị, tại sao bạn đánh dấu biến là 'const'? –

Trả lời

5

const_cast không loại bỏ const-ness của biến như được xác định. Nếu bạn chuyển một biến không const bằng tham chiếu đến phương thức tham chiếu const như void foo(const int& x) thì bạn có thể sử dụng const_cast để sửa đổi giá trị x trong phạm vi foo, nhưng chỉ khi biến mà bạn thực sự chuyển vào không phải là địa điểm đầu tiên.

15

Đây là một trong các trường hợp một phép đúc const không được xác định, vì mã có thể được tối ưu hóa sao cho w không thực sự là một biến và không thực sự tồn tại trong mã được biên dịch.

Hãy thử như sau:

const volatile int w = 10; 
int &wr = const_cast <int &> (w); 
wr = 20; 
std::cout << w << std::endl; 

Nhưng dù sao, tôi sẽ không khuyên lạm dụng const_cast như thế.

+3

Sự khác biệt kỳ diệu là từ khoá 'dễ bay hơi '. Lấy nó ra và w = 10 giống như trong ví dụ dựa trên con trỏ ban đầu của Narendra. –

+1

Bạn đúng, bộ định tính dễ bay hơi được sử dụng để giữ trình biên dịch không tối ưu hóa w. – rmn

+0

Tôi đã thử cùng trên ba trình biên dịch khác nhau [Visual C++ Express Edition, g ++ và Sun CC compiler], trên cả ba trình biên dịch kết quả là giống nhau. Có sự nhất quán trong các kết quả với tất cả các trình biên dịch và do đó sự nhầm lẫn. Btw, tôi đã thử với biến động và nó đã hoạt động như đã đề cập. –

0

Đoán của tôi là tuyên bố w const cho phép trình biên dịch thực hiện các tối ưu hóa tích cực hơn như chèn giá trị của w và sắp xếp lại hướng dẫn. Wether w dường như thay đổi hay không phụ thuộc vào việc tối ưu hóa nào được áp dụng trong trường hợp chính xác và không nằm trong tầm kiểm soát của bạn.

Bạn không thể ép buộc hoàn toàn const. Các cons_cast nên là một gợi ý cho các lập trình viên rằng họ có thể làm một cái gì đó fishy.

2

Tại sao bạn không thể chỉ liên kết lại hằng số? Vì vậy, thay vì

const int w = 10; 
int* wp = const_cast <int*> (&w); 
*wp = 20; 
// some code 

chỉ giới thiệu hằng số khác nhau với cùng một tên

const int w = 10; 
{ 
    const int w = 20; 
    // the same code 
} 

Nếu "mới" liên tục nên phụ thuộc vào giá trị của riêng mình, bạn nên giới thiệu một hằng số (const int _w = w; const int w = _w * 2;). Các bài tập không cần thiết sẽ được tối ưu hóa bởi trình biên dịch - bởi vì chúng tôi đã thấy nó đã thực hiện tối ưu hóa như vậy, vì đó là lý do tại sao bạn hỏi câu hỏi của bạn.

+0

Yuck. Điều này có thể làm việc, nhưng nó xấu xí. –

+1

Xấu xí là mã 'const_cast' và lắp ráp của bạn, trong khi các hằng số ràng buộc lại là một cách tự nhiên để làm việc với chúng. –

1

Đây là phần bồi dưỡng, cần lưu ý rằng đây là C.Đây là một nền tảng khéo léo phức tạp của việc sử dụng một biến hoặc con trỏ bằng cách sử dụng từ khóa const. Điều này làm nổi bật sự khác biệt giữa biến con trỏ foo và ý nghĩa của nó có thể thay đổi như thế nào bằng cách sử dụng từ khóa đã nói.

 
char const *foo; 

char * const foo; 

const char *foo; 

Tờ khai đầu tiên và cuối cùng, làm cho dữ liệu trỏ đến bởi ‘foo’ read-only, nhưng, bạn có thể thay đổi địa chỉ trỏ đến bởi ‘foo’ ví dụ

 
const *char foo; /* OR char const *foo */ 

char str[] = "Hello"; 

foo = &str[0]; /* OK! */ 

foo[1] = 'h'; /* BZZZZTTT! Compile Fails! */ 

Việc kê khai trung lưu ở trên, làm cho con trỏ read-only, nghĩa là bạn không thể thay đổi địa chỉ của dữ liệu được trỏ đến bởi 'foo'

 
char * const foo; 

char str[] = "Hello"; 

foo = &str[0]; /* BZZZZTTT! Compile Fails! */ 
+0

'const * char foo;' là lỗi –

+0

'char * const foo;' là một lỗi trong C++ (câu hỏi này được gắn thẻ C++) - biến 'const' phải có initializer –

+0

@MM Wow 6 năm sau ... xD – t0mm13b

7

mã ở trên ví dụ dịch sang bộ lắp ráp sau:

movl $10, 28(%esp) //const int i = 10; 
    leal 28(%esp), %eax //int* wp = const_cast <int*>(&i); 
    movl %eax, 24(%esp) //store the pointer on the stack 
    movl 24(%esp), %eax //place the value of wp in eax 
    movl $20, (%eax) //*wp = 20; - so all good until here 
    movl $10, 4(%esp) //place constant value 10 onto the the stack for use in printf 
    movl $.LC0, (%esp) // load string 
    call printf //call printf 

Vì int ban đầu được khai báo không đổi, trình biên dịch có quyền sử dụng thứ e giá trị chữ thay vì giá trị được lưu trữ trên ngăn xếp. Điều này có nghĩa là giá trị không được thay đổi và bạn đang mắc kẹt với bản gốc 10.

Đạo đức của câu chuyện là hằng số thời gian biên dịch nên vẫn không đổi vì đó là những gì bạn đang nói với trình biên dịch. Đạo đức của câu chuyện là việc bỏ đi chòm sao để thay đổi một hằng số có thể dẫn đến những điều xấu.

2

Bạn không nên thay đổi giá trị const. Có một lý do nó là const và cố gắng thay đổi nó rất có thể sẽ chỉ dẫn đến lỗi. Nếu const được lưu trữ trong một phần bộ nhớ chỉ đọc thì bạn sẽ nhận được các vi phạm truy cập.

+1

Đủ công bằng và cũng sẽ là phản ứng đầu tiên của tôi. Nhưng trong thế giới thực, đôi khi bạn phải. "Có một lý do nó là const," giả định, tối thiểu, lập trình viên ban đầu đã làm cho nó const biết những gì ông đã làm. –

+0

@ John: Ngay cả trong thế giới thực cũng không có lý do gì để thay đổi giá trị const. Khắc phục vấn đề cơ bản thay vì lộn xộn xung quanh nó. –

0

Câu hỏi hay. Tôi nghĩ sự nhầm lẫn xuất phát từ thực tế là C++ sử dụng từ khóa 'const' cho hai khái niệm khác nhau tùy thuộc vào ngữ cảnh. Các khái niệm này là các biến không đổi và chỉ đọc.

Khi giá trị của biến ‘const’ có thể được tính trong quá trình biên dịch, nó tạo ra hằng số thực. Các tham chiếu đến hằng số như vậy được thay thế bằng giá trị của nó bất cứ khi nào nó được sử dụng. Đó là lý do tại sao không có vị trí nào trong bộ nhớ có thể thay đổi để ảnh hưởng đến tất cả các vị trí mà nó được sử dụng. Nó giống như sử dụng #define.

Khi giá trị của biến ‘const’ không thể được tính trong quá trình biên dịch, biến này tạo ra biến chỉ đọc. Nó có một vị trí trong bộ nhớ có chứa một giá trị nhưng trình biên dịch thực thi một hành vi chỉ đọc.

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