C++严格别名规则与未定义行为:代码是否违规触发UB?
严格别名规则违规与未定义行为分析
代码背景
待审查的模板函数如下:
template <typename DestType, typename SourceType> inline void transferDataAndUpdateSpan(MyArray<DestType>& to, MySpan<const SourceType>& source) { static_assert(sizeof(DestType) == sizeof(SourceType), "Data size mismatch!!"); to.resize(source.size()); memcpy(to.data(), source.data(), sizeof(SourceType) * source.size()); source = { (SourceType*)to.data(), to.size() }; }
注:MySpan是std::span的别名,MyArray是可接收指针与大小的容器。
核心问题解答
1. 是否违反严格别名规则?
答案是:当DestType和SourceType不属于严格别名规则的例外情况时,会违反规则。
严格别名规则的核心要求是:不同类型的指针不能用来访问同一块内存,除非满足特定例外——比如用char*/unsigned char*/std::byte*访问任意类型内存,或者两个类型是标准布局且有共同初始序列,或者其中一个是另一个的基类等。
这里to.data()返回DestType*,被强制转换为SourceType*,如果这两个类型是完全无关的(比如int和std::string,或者float和自定义结构体),后续通过source(指向const SourceType的span)访问这块原本存储DestType对象的内存,就直接违反了严格别名规则。
只有当DestType和SourceType是同一类型,或者符合上述例外条件时,才不会违反规则。但模板本身没有对这两个类型做限制,所以只要传入不兼容的类型,就会触发规则违规。
2. 是否触发未定义行为(UB)?
答案是:会触发UB,且存在多重原因。
- 首先,违反严格别名规则本身就是C++标准明确规定的UB场景,编译器可能会基于"不同类型指针不会指向同一块内存"的假设做优化,导致代码运行时出现数据错乱、读取到脏值等不可预料的问题。
- 其次,
MyArray<DestType>管理的内存中存储的是DestType对象,强制转换为SourceType*后,相当于把这些内存当作SourceType对象来使用。如果SourceType有非平凡的构造/析构函数,或者内存没有被正确初始化为SourceType对象的状态,那么访问这些"伪SourceType对象"也属于UB。
举个简单例子:如果DestType是int,SourceType是double,把int的内存直接当作double访问,既违反严格别名,又属于访问未正确构造的double对象,完全是未定义行为。
内容的提问来源于stack exchange,提问作者Dean
相关产品推荐
相关产品推荐

