C++标准中支撑std::memset使用约束的规则是什么
std::memset使用约束的C++标准依据
std::memset参考文档指出:
std::memset// 定义于头文件 <cstring> void* memset( void* dest, int ch, std::size_t count );[...] 若目标对象是potentially-overlapping subobject(潜在重叠子对象),或不属于*TriviallyCopyable(可平凡复制)*类型(例如标量、C兼容结构体、可平凡复制类型的数组),则行为未定义。
上述限制的依据全部来自C++标准的正式规则,核心可以拆成两部分:
- 为什么要求目标类型必须是可平凡复制类型
std::memset是纯粹的字节级填充函数,执行逻辑就是从目标地址开始,把连续count个字节全部设置为ch转换后的无符号字符值,完全不感知目标位置的对象类型语义。
标准中只有满足可平凡复制要求的类型,其对象值完全由占用的字节内容决定:这类类型没有自定义的非平凡构造、析构、拷贝/移动逻辑,不存在虚表指针、虚基类偏移表这类编译器生成的隐藏状态,也没有依赖构造过程建立的类不变量。对这类类型的对象做字节级覆写,得到的字节序列可以对应到一个合法的对象值。
如果对非可平凡复制类型的对象调用memset,要么会直接破坏对象维持正常行为必需的内部状态(比如把虚表指针覆写为垃圾值),要么因为字节覆写不会触发对应的构造/初始化逻辑,根本不会在目标位置生成合法的该类型对象,后续任何对该对象的访问都属于未定义行为。 - 为什么禁止对潜在重叠子对象调用
memset
潜在重叠子对象是标准定义的特殊子对象,最常见的场景是虚继承体系中的基类子对象、标记了no_unique_address属性的非静态数据成员。这类子对象的内存布局完全由编译器实现决定,可能和完整对象内的其他子对象共享内存空间,不存在标准保证的、完全属于该子对象的连续独立字节区间。
这种场景下调用memset时,传入的count参数没有办法保证刚好覆盖且不超出该子对象的实际存储范围,大概率会覆写到共享内存里其他子对象的内容;同时标准也明确规定,直接通过字节操作修改潜在重叠子对象的完整存储本身就属于未定义行为,和实际是否发生越界覆写无关。
内容的提问来源于stack exchange,提问作者dfrib
相关产品推荐
相关产品推荐

