可变成员是否禁用不可变成员的常量优化
Does mutable member disable const optimizations for non-mutable members?
我所知C++具有相同访问控制的结构/类成员按声明顺序存储在内存中。是下一个示例m
和c
应该一个接一个地存储:
#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
成员是否禁用了整个struct
的const
优化(以某种方式使所有成员都mutable
(?
是否可以将struct
的一部分存储在只读内存中,而将其他部分存储在非只读内存中并遵守标准内存布局C++?
这是在Windows 7上使用Visual Studio 2010和Ubuntu上的GCC 4.7.2进行测试的。
该标准在许多地方谈论mutable
成员。我在下面引用标准的三个部分,解释您只能修改const
对象的mutable
成员。否则就是未定义的行为。
<小时 />3.9.3 CV限定符[基本类型限定符]
const 对象是类型为
const T
的对象或此类对象的不可变子对象。[...]
7.1.1 存储类说明符 [dcl.stc]
类数据成员上的
mutable
说明符使应用于包含类对象的 const 说明符无效,并允许修改mutable
类成员,即使对象的其余部分const
。[...]
7.1.6.1 简历限定词 [dcl.type.cv]
除了可以修改声明
mutable
(7.1.1( 的任何类成员之外,任何在const
对象的生存期 (3.8( 期间修改其尝试都会导致未定义的行为。
是否可以将
struct
的一部分存储在只读内存中,而将其他部分存储在非只读内存中并遵守标准内存布局C++?
不,不可能将struct
(或class
(的一部分存储在与对象其余部分不同的内存区域中。
解释为什么编译器在存储struct
的位置时必须"全有或全无":在大多数处理器中,内存页为 4KB(少数有 8KB 页(。这就是"只读"与"读/写"内存块的粒度。因此,您不能在只读内存中有一个 4 字节整数,然后在读写内存中有一个下一个 4 字节整数(除非它们完全跨越 4KB 内存边界 - 但如果你有一个包含 3000 个内存的数组,占用 12MB,这肯定会浪费内存(。
请注意,这不是"优化"。只读存储器并不比读写存储器快。这是一种保护,防止用户愚蠢地使用const
并写入他们不应该写入的数据。
此外,如果您添加一个对struct
"做某事"的构造函数,它很可能会将结构存储在读写内存中,因为编译器生成代码以在运行时打开和关闭只读非常棘手。
关键字"const"更像是程序员团队的标签,如"private"和"public",而不是编译器指令或编译器提示。编译器可以使用它来进行优化,但不需要这样做。编译器只需要控制滥用并防止滥用。所以你看到的行为是完全可以的。不,一个结构实例或类实例的某些部分不可能存在于不同的内存区域中(不计算映射(。因为该决定会影响结构的使用,并且必须得到程序员的允许。
- 私有类型的静态常量成员
- constexpr构造函数需要常量成员函数时出现问题
- 是否可以同时声明一个类成员的常量/非常量?
- 当成员值从指针更改为非指针时,C++常量问题
- 常量公共成员有什么问题?
- Clang 格式 10.0 与 5.0 常量成员函数的格式不同
- C++/QT:使用指向私有成员的常量指针作为只读数据共享
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 初始化依赖于子类的继承类的常量类成员
- 常量成员函数中成员变量的类型
- 如何为非常量和常量重载实现一次成员函数?
- 如何处理运算符=中的常量成员?
- 移动类的成员作为常量引用参数传递
- 为什么我可以改变常量对象中的成员变量,这是返回常量对象函数的结果?
- 常量和引用成员函数限定符
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 常量成员和没有setter的私有成员之间有什么区别
- 如何初始化类C++的成员常量向量
- 当我希望调用基类构造函数时,如何在派生类中初始化成员常量引用