【问题标题】:Modifying a const through a non-const pointer通过非常量指针修改 const
【发布时间】:2011-01-31 07:18:13
【问题描述】:

我对以下代码中发生的事情有点困惑:


const int e = 2;

int* w = ( int* ) &e;          // (1) cast to remove const-ness
*w = 5;                        // (2)

cout &lt&lt *w &lt&lt endl;            // (3) outputs 5
cout &lt&lt e &lt&lt endl;             // (4) outputs 2

cout &lt&lt "w = " &lt&lt w &lt&lt endl;   // (5) w points to the address of e
cout &lt&lt "&e = " &lt&lt &e &lt&lt endl;

在(1)中,w指向e的地址。在 (2) 中,该值更改为 5。但是,当显示 *w 和 e 的值时,它们的值不同。但是如果你打印 w 指针和 &e 的值,它们的值/地址是相同的。

为什么 e 仍然包含 2,即使它已更改为 5?它们是否存储在单独的位置?还是临时的?但是w指向的值怎么还是e的地址呢?

【问题讨论】:

  • 你处于未定义的行为领域——任何事情都有可能发生。
  • 我的大脑太累了,看不出发生了什么,但你可以使用 const_cast 来做这件事。如果您只是想了解正在发生的事情,您可以忽略此评论。
  • @erelender:您可以为此使用const_cast,但这不会使行为变得更不确定。

标签: c++ pointers casting const-correctness


【解决方案1】:

正如我在评论中所说,一旦你修改了 const 值,你就处于未定义的行为状态,所以谈论正在发生的事情没有多大意义。但到底是什么..

cout << *w << endl;            // (3) outputs 5
cout << e << endl;             // (4) outputs 2

据推测,*w 正在运行时进行评估,但 e 被视为编译时间常量

【讨论】:

  • 也许...另一种可能是编译器在之前注意到“*w=5”并在第一行插入了 5 而不是 *w
  • 我同意。在范围内初始化的 const int 将是一个编译时间常数。
  • 这是否意味着将 const 变量转换为非常量指针是没有用的,因为通过该指针进行修改会导致未定义的行为?
  • 差不多,const 的全部意义在于你不修改值......你永远不应该抛弃 const。
  • 我同意尼尔的观点,对于更长的解释const X c = v,其中X 是枚举或整数类型,v 是整数常量表达式(即const int v = 5;)定义了一个常量c 本身可以用作整数常量表达式。这意味着编译器可以在编译任何使用 c 时内联该值,这很可能发生。 UB 是通过const_cast 修改该常量(C 风格转换为const_cast)可能会做任何事情或根本不做任何事情,包括终止应用程序。在这种特殊情况下,它正在修改值。
【解决方案2】:

我怀疑你正在绊倒编译器。它不指望你用 e 玩坏事,所以当它看到这条线时:

cout << e << endl;

它只是插入值 2 而不是查找实际值。您可以通过查看程序的反汇编来验证(或反驳)这一点。

【讨论】:

    【解决方案3】:

    我猜编译器已经优化了值输出。它看到 e 是 const (因此,理论上它不能改变)并将 cout &lt;&lt; e &lt;&lt; endl; 更改为 cout &lt;&lt; 2 &lt;&lt; endl;。但是,e 仍然必须存在,因为它被 w 使用,所以 w 正确地获取了它的地址并修改了它的值,但是你在 cout 中看不到它。

    故事的寓意——只有在你真正想成为const 时才声明事情const。抛弃constness 不是一个好主意。

    【讨论】:

      【解决方案4】:

      我唯一能想到的是编译器对代码进行了一些优化,即使它为 e 分配了内存,对 e 的任何引用都被替换为值 2

      所以实际上(影响?)注释 (4) 处的行被“优化”为

      cout << "2" << endln;
      

      【讨论】:

        【解决方案5】:

        我猜编译器使用 constness 来优化变量并在代码中插入一个固定值。

        【讨论】:

          【解决方案6】:

          C++14 标准的 [dcl.type.cv]/4 部分涵盖了这一点(早期标准也有类似的文本):

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

          e 是一个 const 对象,*w = 5; 尝试修改该对象,因此结果为 undefined behavior

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-03
            • 2020-10-04
            • 2016-05-25
            • 2016-07-18
            相关资源
            最近更新 更多