在C ++中更改const变量的值

时间:2010-01-05 13:07:06

标签: c++ const

我正在尝试更改变量的值,该变量定义为int const,如下所示。

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
const int i = 10;

w的值不会改变。

在第一种情况下,为什么w的值没有改变,即使w和wp指向相同的内存位置[这是我打印地址时的印象]

它对编译器的不同之处在于它对这两种情况的区别对待?

有没有办法确保w不会失去常数,无论它的定义方式如何?

8 个答案:

答案 0 :(得分:15)

这是未定义const转换的情况之一,因为代码可能已经过优化,因此w实际上不是变量,并且在编译代码中并不存在。

尝试以下方法:

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

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

答案 1 :(得分: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。

故事的寓意是编译时常量应该保持不变,因为这是你告诉编译器的。故事的寓意是,为了改变常数而抛弃常数会导致坏事。

答案 2 :(得分:5)

const_cast不会消除定义的变量的常量。如果您通过引用将非const变量传递给采用void foo(const int& x)等const引用的方法,那么您可以使用const_cast来修改xfoo的值},但仅当您实际传入的变量首先不是const时。

答案 3 :(得分: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
}

如果“new”常量应该取决于它自己的值,则应该引入另一个常量(const int _w = w; const int w = _w * 2;)。不必要的任务将由编译器进行优化 - 因为我们已经看到它已经进行了这样的优化,因为这就是你提出问题的原因。

答案 4 :(得分:2)

您不应该更改const值。它是const的原因并且试图改变它很可能只会导致错误。如果const存储在只读存储器部分中,那么您将获得访问冲突。

答案 5 :(得分:1)

这是一个复习,应该注意这是在C中。这是使用const关键字使用变量或指针的一个看似棘手的基础。这突出了指针变量foo之间的区别,以及它的含义如何通过使用所述关键字来改变。

char const *foo;

char * const foo;

const char *foo;

第一个和最后一个声明,使'foo'指向的数据只读,但是,你可以改变'foo'指向的地址,例如。

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

char str[] = "Hello";

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

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

上面的中间声明,使指针只读,即你不能改变'foo'指向的数据的地址

char * const foo;

char str[] = "Hello";

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

答案 6 :(得分:1)

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

当编译期间可以计算'const'变量的值时,它会创建一个真常量。无论何时使用,都会将对此类常量的引用替换为其值。这就是为什么内存中没有位置可以更改以影响使用它的所有位置。这就像使用#define。

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

答案 7 :(得分:0)

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

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