2
int main()
{
    const int maxint=100;//The program will crash if this line is put outside the main
    int &msg=const_cast<int&>(maxint);  
    msg=200;  
    cout<<"max:"<<msg<<endl; 
    return 0;
}

如果 'const int maxint=100;' 该函数将运行正常 定义放在主函数内,但如果放在外面,则会崩溃并弹出一条错误消息,称“访问冲突”。

有人说这是某种“未定义的行为”,我想知道确切的答案以及如何安全地使用 const 演员?

4

3 回答 3

9

他们是正确的,这是未定义的行为。你不能修改const变量的值,这是抛弃const某些东西的危险:你最好知道它不是真的const.

编译器看到它maxintconst并且不应该修改,甚至不需要给它一个地址。maxint如果它认为合适,它可以用 100 替换所有用途。正如 Matteo Italia 指出的那样,它也可能只是将常量放入只读内存的一部分,这可能是你正在发生的事情。这就是为什么修改它会产生未定义的行为。

唯一可以安全地抛弃const变量的方法是,如果变量实际上不是const,而是将const限定符添加到非const变量,如下所示:

int f(const int& x) {
    int& nonconst = const_cast<int&>(x);

    ++nonconst;
}

int blah = 523;

f(blah); // this is safe

const int constblah = 123;

f(constblah); // this is undefined behaviour

想想这个编译完美的例子:

int f(const int& x) {
    int& nonconst = const_cast<int&>(x);

    ++nonconst;
}

int main() {
    f(4); // incrementing a number literal???
}

你可以看到 usingconst_cast是多么危险,因为没有办法真正判断一个变量是否是原来的const。您应该尽可能避免使用const_cast(使用函数,只是不接受const参数)。

于 2011-12-29T02:09:56.563 回答
5

修改一个对象const(除了可变成员)会导致未定义的行为(来自 C++03 标准):

7.1.5.1/4“简历限定词”

除了可以修改任何声明为 mutable (7.1.1) 的类成员外,任何在 const 对象的生命周期 (3.8) 期间修改它的尝试都会导致未定义的行为。

上述未定义的行为在标准的部分中特别提到const_cast

5.2.11/7“常量演员”

[注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写操作由 const_cast 产生,该 const_cast 丢弃了 const-qualifier68)可能会产生未定义的行为(7.1.5.1)。]

因此,如果您有一个const指向实际上不是 的对象的指针或引用,则const允许您写入该对象(通过丢弃常量),但如果该对象确实是const.

例如,允许编译器将const对象放置在只读存储中。不过,它不必这样做,而且显然不适用于不会崩溃的测试代码。

于 2011-12-29T02:25:59.300 回答
0

你只被允许抛弃已知不是的对象的常量const。例如,接口可能通过使用const指针或const引用传递对象,但您传入的对象不是const并且想要/需要修改它。在这种情况下,抛弃 constness 可能是正确的。

另一方面,抛弃一直存在的对象的 constnessconst可能会让你陷入大麻烦:当访问这个对象时,尤其是写入它时,系统可能会导致各种奇怪的事情:行为未定义(根据 C++ 标准)并且在特定系统上,它可能导致例如访问冲突(因为对象的地址被安排在只读区域中)。

请注意,尽管有另一个响应,但我看到const对象需要分配一个地址,如果该地址曾经以某种方式被占用和使用。在您的代码中,const_cast<int&>(maxint)表达式基本上获得了常量 int 的地址,该地址显然存储在标记为只读的内存区域中。您的代码片段的有趣方面是它显然工作,特别是在打开优化时:代码足够简单,编译器可以判断出更改的位置并没有真正使用,并且实际上并没有尝试更改内存位置!在这种情况下,不会报告访问冲突。这显然是在函数内部声明常量时的情况(尽管常量也可能位于通常不能标记为只读的堆栈上)。您的代码的另一个潜在结果是(与常量是否在函数内部声明无关)实际上已更改,有时读为 100,而在其他上下文中(以某种方式涉及地址)为 200。

于 2011-12-29T02:25:20.640 回答