本文介绍了使用aligned_storage时如何避免严格的别名错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 std :: aligned_storage 作为变体模板的后备存储.问题是,一旦我在gcc上启用 -O2 ,我就会开始收到取消引用类型化指针的警告会破坏严格的别名"的警告.

I'm using std::aligned_storage as the backing storage for a variant template. The problem is, once I enable -O2 on gcc I start getting warnings of 'dereferencing type-punned pointer will break strict aliasing`.

真正的模板要复杂得多(在运行时检查类型),但是生成警告的最小示例是:

The real template is much more complex (type checked at runtime), but a minimal example to generate the warning is:

struct foo
{
  std::aligned_storage<1024> data;

  // ... set() uses placement new, stores type information etc ...

  template <class T>
  T& get()
  {
    return reinterpret_cast<T&>(data); // warning: breaks strict aliasing rules
  }
};

我很确定 boost :: variant 与此基本相同,但是我似乎找不到他们如何避免此问题的方法.

I'm pretty sure boost::variant is doing essentially the same thing as this, but I can't seem to find how they avoid this issue.

我的问题是:

  • 如果以这种方式使用 aligned_storage 违反了严格混叠,我应该如何使用它?
  • 考虑到函数中没有其他基于指针的操作, get()中是否确实存在严格的混叠问题?
    • 如果内联 get()怎么办?
    • get()= 4怎么样?get()= 3.2 ?由于 int float 是不同的类型,该序列是否可以重新排序?
    • If using aligned_storage in this way violates strict-aliasing, how should I be using it?
    • Is there actually a strict-aliasing problem in get() given that there are no other pointer based operations in the function?
      • What about if get() is inlined?
      • What about get() = 4; get() = 3.2? Could that sequence be reordered due to int and float being different types?

      推荐答案

      std :: aligned_storage < type_traits> 的一部分;像该头文件的其余大多数居民一样,它只是某些typedef的持有人,并不意味着被用作数据类型.它的工作是获取大小和对齐方式,并为您提供具有这些特征的POD类型.

      std::aligned_storage is part of <type_traits>; like most of the rest of the inhabitants of that header file, it is just a holder for some typedefs and is not meant to be used as a datatype. Its job is to take a size and alignment, and make you a POD type with those characteristics.

      您不能直接使用 std :: aligned_storage< Len,Align> .您必须使用 std :: aligned_storage< Len,Align> :: type ,即转换后的类型,该类型是"POD类型,适用于任何大小最大为 Len ,并且其对齐方式是 Align 的除数."( Align 默认为大于或等于 Len 的最大有用对齐方式.)

      You cannot use std::aligned_storage<Len, Align> directly. You must use std::aligned_storage<Len, Align>::type, the transformed type, which is "a POD type suitable for for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align." (Align defaults to the largest useful alignment greater than or equal to Len.)

      正如C ++标准所指出的那样, std :: aligned_storage 返回的类型通常是带有对齐说明符的 unsigned char 的数组(具有指定大小).这样可以避免使用没有严格的别名"规则,因为字符类型可以别名任何其他类型.

      As the C++ standard notes, normally the type returned by std::aligned_storage will be an array (of the specified size) of unsigned char with an alignment specifier. That avoids the "no strict aliasing" rule because a character type may alias any other type.

      所以您可能会做类似的事情:

      So you might do something like:

      template<typename T>
      using raw_memory = typename std::aligned_storage<sizeof(T),
                                                       std::alignment_of<T>::value>::type;
      
      template<typename T>
      void* allocate() { return static_cast<void*>(new raw_memory<T>); }
      
      template<typename T, typename ...Arg>
      T* maker(Arg&&...arg) {
         return new(allocate<T>()) T(std::forward<Arg>(arg)...);
      }
      

      这篇关于使用aligned_storage时如何避免严格的别名错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 12:18