【问题标题】:Does mutable member disable const optimizations for non-mutable members?可变成员是否禁用非可变成员的 const 优化?
【发布时间】:2013-09-03 07:10:20
【问题描述】:

据我所知,在 C++ 中,具有相同访问控制的结构/类成员按声明顺序存储在内存中。下一个示例 mc 是否应该一个接一个地存储:

#include <cstdlib>
#include <iostream>

struct X
{
    mutable int m;
    int         c;
};

const X cx = {0, 1};

int main()
{   
    X& x = const_cast<X&>(cx);

    x.m = rand();
    x.c = rand();

    std::cout<<x.m<<" "<<x.c;
}

在本例中,程序运行并打印 2 个随机数。如果我删除 mutable 它会崩溃,因为 cx 存储在只读受保护的内存中。

这让我想知道 - 一个 mutable 成员是否会禁用整个 structconst 优化(不知何故让所有成员 mutable)?

是否可以将struct 的一部分存储在只读内存中,而将其他部分存储在非只读内存中并遵守 C++ 标准内存布局?

这是使用 Windows 7 上的 Visual Studio 2010 和 Ubuntu 上的 GCC 4.7.2 测试的。

【问题讨论】:

    标签: c++ constants mutable


    【解决方案1】:

    标准在很多地方都谈到mutable 成员。我在下面引用标准的三个部分来解释您只能修改const 对象的mutable 成员。否则它是未定义的行为

    3.9.3 CV 限定符 [basic.type.qualifier]

    const 对象const T 类型的对象或此类对象的非可变子对象。

    [...]

    7.1.1 存储类说明符 [dcl.stc]

    类数据成员上的 mutable 说明符使应用于包含类对象的 const 说明符无效,并允许修改 mutable 类成员,即使该对象的其余部分是 const

    [...]

    7.1.6.1 cv 限定符 [dcl.type.cv]

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


    是否可以将struct 的一部分存储在只读内存中,而将其他部分存储在非只读内存中并遵守 C++ 标准内存布局?

    不,不可能将struct(或class)的一部分存储在与对象其余部分不同的内存区域中。

    【讨论】:

    • 所以main 中的x.c = rand(); 在这两种情况下都会触发UB,对吗?
    • @Hulk 是的,m 上的 mutable 关键字不会改变 c 的任何内容。看看这个帖子:stackoverflow.com/a/583150/1394283。它很好地解释了我引用的标准的最后一部分。
    【解决方案2】:

    解释为什么编译器在存储struct 的位置时必须“全有或全无”:在大多数处理器中,内存页为 4KB(少数有 8KB 页)。这是“只读”与“读/写”内存块的粒度。所以你不能在只读内存中有一个 4 字节整数,然后在读写内存中有下一个 4 字节整数(除非它们正好跨越 4KB 内存边界 - 但这肯定会造成相当浪费的使用内存,如果你有 3000 个数组,占用 12MB)。

    请注意,这不是“优化”。只读存储器并不比读写存储器快。这是一种保护,防止用户对const 感到愚蠢并写入他们不应该写入的数据。

    此外,如果您向struct 添加一个“做某事”的构造函数,它很可能会将结构存储在读写内存中,因为编译器生成代码以打开只读和在运行时关闭。

    【讨论】:

    • 我添加了初始化 m 和 c 的 X() 构造函数,并且 cx 不像以前那样在只读内存中。非常有趣的见解,谢谢!
    【解决方案3】:

    关键字“const”更像是程序员团队的标签,例如“private”和“public”,而不是编译器指令或编译器提示。编译器可以使用它进行优化,但不需要。编译器只需要控制和防止滥用。所以你看到的行为是完全可以的。 不,一个结构实例或类实例的部分不可能存在于不同的内存区域(不计入映射)。因为该决定会影响结构的使用,并且必须得到程序员的允许。

    【讨论】:

    • “关键字“const”更像是程序员团队的标签”——恐怕在这种情况下,这个团队的成员可能对这个标签的含义略有不同的看法。
    • 我的意思是,最好的解释是——“const 限定符是对编译器的一条指令,用于拒绝尝试直接修改该对象的代码;尝试间接修改该对象......导致未定义行为,意味着任何结果都是可能的。” (stackoverflow.com/questions/4275504/…)
    • 你是对的。我的回复写得很仓促。尽管如此,在我看来,它更具人类可读性。是的,多年来在不同的团队工作,我总是对人们如何试图欺骗编译器并期望以正确的方式工作感到惊讶。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多