更改 C++ 中 const 变量的值[重复]

问题描述 投票:0回答:8

我正在尝试更改定义为

const int
的变量的值,如下所示:

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

w
的值没有改变,即使在赋值之后也是10,尽管看起来
w
wp
都指向同一个内存位置。但如果在声明时定义如下,我可以更改
w
的值:

int i = 10;
const int w = i;

如果我更改

i
的声明以使其成为常量,如下所示:

const int i = 10;

w
的值不会改变。

在第一种情况下,为什么

w
的值没有改变,即使
w
wp
指向相同的内存位置(这是我打印它们的地址时得到的印象)。

编译器以不同方式处理这两种情况有什么区别?

有没有办法确保

w
不会失去常量,无论它的定义方式如何?

c++ constants
8个回答
16
投票

这是 const 强制转换未定义的情况之一,因为代码可能经过优化,使得 w 并不是真正的变量,并且在编译的代码中并不真正存在。

尝试以下操作:

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

无论如何,我不建议这样滥用 const_cast 。


8
投票

上面示例中的代码转换为以下汇编程序:

    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

因为原来的 int i 被声明为常量,所以编译器保留使用字面值而不是存储在堆栈上的值的权利。这意味着该值不会更改,并且您将停留在原始 10 上。

这个故事的寓意是编译时常量应该保持不变,因为这就是您告诉编译器的内容。这个故事的寓意是,为了改变常量而抛弃常量可能会导致坏事。


5
投票

const_cast
不会消除定义的变量的常量性。 如果您要通过引用将非常量变量传递给采用 const 引用(如
void foo(const int& x)
)的方法,那么您可以使用
const_cast
来修改
x
内的
foo
的值,但前提是该变量是实际上传入的值一开始就不是 const。


2
投票

为什么不能重新绑定常量? 所以而不是

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

只需引入同名的不同常量即可

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

如果“新”常量应该依赖于它自己的值,则应该引入另一个常量(

const int _w = w; const int w = _w * 2;
)。 不必要的分配将被编译器优化——因为我们已经看到它已经做了这样的优化,因为这就是你问问题的原因。


2
投票

您不应该更改 const 值。它是 const 是有原因的,尝试更改它很可能只会导致错误。如果常量存储在只读内存部分中,那么您将遇到访问冲突。


1
投票

好问题。我认为这种混乱来自于 C++ 根据上下文使用关键字“const”来表示两个不同的概念。这些概念是常量和只读变量。

当可以在编译期间计算“const”变量的值时,它会创建一个真正的常量。 每当使用该常量时,对该常量的引用都会被其值替换。这就是为什么内存中没有任何位置可以更改以影响所有使用它的地方。就像使用#define 一样。

当编译期间无法计算“const”变量的值时,它会创建一个只读变量。它在内存中有一个位置包含一个值,但编译器强制执行只读行为。


1
投票

这里复习一下,应该注意的是,这是用 C 语言编写的。这是使用

const
关键字使用变量或指针的一个看似棘手的基础。这突出了指针变量
foo
之间的区别以及如何通过使用所述关键字来改变它的含义。

char const *foo;

char * const foo;

常量 char *foo;

第一个和最后一个声明,使“foo”指向的数据为只读,但是,您可以更改“foo”指向的地址,例如

const *char foo; /* 或 char const *foo */ char str[] = "你好"; foo = &str[0]; /* 好的! */ foo[1] = 'h'; /* 嗡嗡嗡!编译失败! */

上面的中间声明,使

指针只读,即你不能更改'foo'指向的数据的地址

char * const foo; char str[] = "你好"; foo = &str[0]; /* 嗡嗡嗡!编译失败! */
    

0
投票
我的猜测是,声明 w const 允许编译器执行更积极的优化,例如内联 w 的值和重新排序指令。 w 是否会发生变化取决于在具体情况下应用了哪些优化,并且不受您的控制。

你不能强迫 w 完全是 const。 cons_cast 应该向程序员暗示他们可能正在做一些可疑的事情。

© www.soinside.com 2019 - 2024. All rights reserved.