严格的别名规则和新的安置

dig*_*ale 2 c++ strict-aliasing placement-new

IsoCpp.org提供有关新展示位置的常见问题解答:

他们提供的例子是:

#include <new>        // Must #include this to use "placement new"
#include "Fred.h"     // Declaration of class Fred
void someCode()
{
  char memory[sizeof(Fred)];     // Line #1
  void* place = memory;          // Line #2
  Fred* f = new(place) Fred();   // Line #3 (see "DANGER" below)
  // The pointers f and place will be equal
  // ...
}
Run Code Online (Sandbox Code Playgroud)

不会上面的代码违反因为C++的严格别名规则placememory是不同的类型,但引用相同的存储器的地址?

(我知道类型的指针char可以别名任何其他类型,但是在这里我们似乎有一个void*别名a char*,这是我不理解的?)

我怀疑大多数内存分配器也会以类似的方式违反严格的别名规则.使用贴图新内容时遵循严格别名规则的正确方法是什么?

谢谢

Cor*_*lks 5

使用新放置时遵守严格别名规则的正确方法是什么?

正确的方法是使用std::aligned_storage. 该代码示例不能保证 的正确存储对齐Fred,因此不应使用它。

正确的方法是:

#include <new>         // For placement new
#include <type_traits> // For std::aligned_storage

struct Fred {
  // ...
};

void someCode() {
  std::aligned_storage<sizeof(Fred), alignof(Fred)>::type memory;
  // Alternatively, you can remove the "alignof(Fred)" template parameter if you
  // are okay with the default alignment, but note that doing so may result in
  // greater alignment than necessary and end up wasting a few bytes.
  Fred* f = new(&memory) Fred();
}
Run Code Online (Sandbox Code Playgroud)

由于位置和内存是不同的类型,但引用相同的内存位置,上面的代码是否会违反 C++ 的严格别名规则?

现在,对于您对原始代码中fplace、 和之间的别名的担忧memory,请注意,不存在任何别名冲突。严格的别名规则意味着您不能“取消引用为不兼容类型别名的指针”。由于您无法取消引用 a void*(并且将指针转换为 a 或从 a 转换是合法的void*),因此不存在place导致严格别名冲突的风险。


Mar*_*ica 5

没有问题,因为代码没有引用*place.只是让指针相等不会导致UB - 它通过它们两个被禁止的方向.

例如,以下是合法的:

 struct A {int x;} a;
 struct B {} *pb = reinterpret_cast<B*>(&a);
 A* pa = reinterpret_cast<A*>(pb);
Run Code Online (Sandbox Code Playgroud)

请参阅*pb并且您违反了严格的别名规则.

当然,在你的特定例子中,你不能写,*place因为这会产生一个void不允许的左值类型.

还要注意Cornstalks的观点:该示例确实需要使用,std::aligned_storage因为无法保证memoryFred对象正确对齐.在实践中,这通常无关紧要,因为您将使用类似newmalloc(确实返回适当对齐的存储)为新的位置分配内存.