这真的打破了严格别名规则吗?

Red*_*ert 31 c++ strict-aliasing language-lawyer

当我使用g ++编译这个示例代码时,我收到此警告:

警告:解除引用类型惩罚指针将破坏严格别名规则 [-Wstrict-aliasing]

代码:

#include <iostream>

int main() 
{
   alignas(int) char data[sizeof(int)];
   int *myInt = new (data) int;
   *myInt = 34;

   std::cout << *reinterpret_cast<int*>(data);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不是data别名int,因此将其强制转换为int不会违反严格的别名规则?或者我在这里遗漏了什么?

编辑:奇怪,当我这样定义时data:

alignas(int) char* data = new char[sizeof(int)];
Run Code Online (Sandbox Code Playgroud)

编译器警告消失了.堆栈分配是否与严格别名产生差异?事实上它是一个char[]而不是一个char*意味着它实际上不能为任何类型别名吗?

Col*_*mbo 22

警告是绝对合理的.腐朽指针data没有指向类型的对象int,和铸造它不会改变这一点.见[basic.life]/7:

如果在对象的生命周期结束之后并且在重用或释放对象占用的存储之前,则在原始对象占用的存储位置创建新对象,指向原始对象的指针,引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用来操纵新对象,如果:
(7.1) - [.. ]
(7.2) - 新对象与原始对象的类型相同(忽略顶级cv限定符),

新对象不是一个数组char,而是一个int.P0137规范了指向的概念,它补充说launder:

[ 注意:如果不满足这些条件,可以通过调用std::launder(18.6 [support.dynamic])从表示其存储地址的指针获取指向新对象的指针.- 结束说明 ]

即你的片段可以这样纠正:

std::cout << *std::launder(reinterpret_cast<int*>(data));
Run Code Online (Sandbox Code Playgroud)

..或者只是从placement new的结果中初始化一个新指针,这也会删除警告.

  • @supercat:memcpy 和 memmove 的相对效率与此问答有何关系? (2认同)
  • 为什么自gcc 7.2起警告完全消失?直播(https://godbolt.org/g/ci5dKj) (2认同)