【问题标题】:A const & refers to a nonvolatile variable. The variable changes. Does the change invalidate the const &?const & 指的是非易失性变量。变量发生变化。更改是否使 const & 无效?
【发布时间】:2019-02-21 16:03:53
【问题描述】:

在 C++ 中,const & 的值可以改变吗?

嗯,当然不能改变,不是吗?这就是const 的意思。此外,请听 Stroustrup:

const 左值引用指的是一个常量,从引用用户的角度来看,它是不可变的。

但是这个呢?

#include <iostream>

int main() {
    int           a = 0;
    const int&    r = a;
    const int old_r = r;
    ++a;
    const int new_r = r;
    std::cout
      <<      "old_r == " << old_r
      << " but new_r == " << new_r << std::endl;
    return 0;
}

在我的机器上,这个输出,old_r == 0 but new_r == 1

这就是我真正的问题。在上面的代码中,看一行

    const int new_r = r;

只要

  • 地址&amp;new_r既没有在这一行也没有在代码的其他地方提取,并且
  • 代码没有volatile

是否会阻止优化编译器将 old_rnew_r 合并为单个常量对象,将行视为如下所示?

    const int& new_r = old_r;

我问是因为,据我所知,如果编译器这样做优化,那可能会改变行为。程序可能会输出old_r == 0 but new_r == 0

相关问题

我发现的最相关的现有问题是这个:

以下也是相关的,但与当前问题不同,涉及演员表:

另见N4659(C++17 标准草案),第 2 节。 10.1.7.1,“cv 限定符。

问题顶部的 Stroustrup 引用来自 sect. C++ 编程语言, 第 4 版的 7.7.2。当然,没有一个作者可以把一千页的书里的每一句话都写得完美无缺。然而,也许 Stroustrup 是清楚的,而我只是把他读错了。不过,您可能会明白为什么这句话让我感到困惑。这就是我问的原因。

【问题讨论】:

  • 当然可以,这也是const T&amp; 参数使函数比按值传递相同参数更难优化的原因之一。

标签: c++ reference constants undefined-behavior const-reference


【解决方案1】:

在 C++ 中,const & 的值可以改变吗?

是的,这是完全合法的。将const&amp; 带入某个变量并不能阻止该变量被修改,它只是意味着您不能通过引用修改该变量。这意味着

int a = 42;
int const& b = a;
++a;
std::cout << a << " " << b;

将打印

43 43

我有没有尝试过

++b;

虽然这将是一个编译器错误,因为b 对该值的访问是const,而++ 是一个非 const 操作。

【讨论】:

  • 这是正确的答案。更改值不需要线程和波动性。
【解决方案2】:

在 C++ 中,const &amp; 的值可以改变吗?

是的,但不是通过那个引用(忽略 mutable 字段)。

void foo(const int& c, int& mut) {
    std::cout << c << " ";
    ++mut; // changes `c` if &c == &mut
    std::cout << c << std::endl;
}

int a = 42;
foo(a, a); // 42 43

是否会阻止优化编译器将 old_r 和 new_r 合并为单个常量对象,将行视为如下所示?

as-if 规则允许编译器在可见副作用相同的情况下进行优化,
不是这里的情况。所以你的代码中的“提议的变量合并”不能幸运地完成。

【讨论】:

  • 啊哈。我知道了。这是可见的副作用规则。我认为这是有道理的。我的想法是const &amp; 应该在语义上暗示该符号引用了一个不变的对象,并且编译器可能依赖于这个暗示。然而,你说事实并非如此。除了线程代码中的锁和原子之外,我从来没有理由将const &amp; 用于非易失性但仍在变化的对象。因此,您的回答很有启发性。
  • 在 C++ 中有什么方法可以让编译器假设通过引用标识的对象不会改变,如果程序员知道是这种情况?在 C99 中,可以使用 const*restrict 指针来表明这一点,但我不知道有任何类似于 C++ 中的 restrict 的概念。
  • @supercat:没有restrict是标准。 (但编译器通常提供等同于__restrict__)。
【解决方案3】:

嗯,当然不能改变,不是吗?这就是 const 的意思。

不,不是。

const 表示无法改变这件事。这并不意味着它不会改变。这并不意味着它是一个常数。

const 只是给你一个不可变的视图。对那件事可能有其他观点,而且这些观点可能是可变的。

是否会阻止优化编译器将 old_r 和 new_r 合并到单个常量对象中

是的:它们中的一个会有错误的值。

【讨论】:

  • 您已经证明我的措辞不正确地表达了我的意图。谢谢你的提示。我已经改写了问题的相关部分。
  • 看起来您并没有改变问题的前提,即您认为绑定const 引用会保证引用对象不会被更改。这本来是很清楚的,但现在更微妙了。如果这不再是问题的前提,那么您能否也澄清一下其余的问题?为什么这是未定义的行为?你认为const 到底做了什么?
  • 不,你已经正确理解了前提。最初的问题吸引了 +2 的支持,但也吸引了 -2 的反对,无法解释。编辑是我的盲目尝试,使问题变得更加平淡,以免被否决票埋没。脸颊在 SO 上获得了反对票。就是这样。
  • 你的时间已经很慷慨了,所以我不再强加。但是,如果您倾向于编辑问题,我们将不胜感激。有时很难发出正确的音调。
  • 是的,我只是把它放回原来的样子。您编辑的那句话(我引用的)似乎是问题的绝对核心。
【解决方案4】:

是的,常量值可以改变。当你这样做时

const int&    r = a;

您正在创建对 const int 的引用。使用此变量的代码将不允许通过引用更改值。但这绝不意味着存储在那里的值不会改变。

将其视为具有只读权限的变量。其他一些代码可能具有写入权限。

您应该与真正的常量表达式constexpr 进行比较。

【讨论】:

  • 我相信这个答案中的第二句话已经是混乱的一部分,因为 const int 肯定不能改变 - 那么为什么当你形成对它的引用时它应该能够改变呢? (“对 const int 的引用”中的“const int”与const int 中的“const int”并不完全相同,请参阅引用绑定。)区别非常微妙,所以我更愿意详细说明这个措辞。
猜你喜欢
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多