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

时间:2016-05-14 18:27:25

标签: c++ strict-aliasing placement-new

IsoCpp.org提供有关新展示位置的FAQ

他们提供的例子是:

#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
  // ...
}

上述代码不会违反C ++的严格别名规则,因为placememory是不同的类型,但引用相同的内存位置?

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

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

谢谢

2 个答案:

答案 0 :(得分:5)

没有问题,因为代码没有引用javah。让指针相等并不会导致UB - 它通过这两个指令是间接的,这是禁止的。

例如,以下是合法的:

*place

请参阅 struct A {int x;} a; struct B {} *pb = reinterpret_cast<B*>(&a); A* pa = reinterpret_cast<A*>(pb); ,并且您违反了严格的别名规则。

在您的特定示例中,您无法撰写*pb因为这会产生*place类型的左值,这是不允许的。

还要注意Cornstalks的观点:该示例确实需要使用void,因为无法保证std::aligned_storage对象memory正确对齐。在实践中,这通常并不重要,因为您将使用Frednew(确实返回适当对齐的存储空间)为新的展示位置分配内存。

答案 1 :(得分:3)

  

使用展示位置时遵循严格别名规则的正确方法是什么?

正确的方法是使用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();
}
  

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

现在,关于原始代码中fplacememory之间的别名问题,请注意,没有任何别名违规。严格别名规则意味着您不能{&#34; dereference a pointer that aliases an incompatible type&#34;。由于您无法取消引用void*(以及将指针转换为/ void*的合法性),因此place没有风险导致严格的别名冲突。