6

std::aligned_storageバリアント テンプレートのバッキング ストレージとして使用しています。問題は、-O2gcc で有効にすると、「タイプがパニングされたポインターを逆参照すると厳密なエイリアシングが壊れる」という警告が表示され始めることです。

実際のテンプレートはもっと複雑です (実行時に型がチェックされます) が、警告を生成するための最小限の例は次のとおりです。

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ていますが、この問題を回避する方法を見つけることができないようです。

私の質問は次のとおりです。

  • このように使用aligned_storageすると厳密なエイリアスに違反する場合、どのように使用すればよいですか?
  • get()関数に他のポインターベースの操作がない場合 、厳密なエイリアシングの問題は実際にありますか?
    • get()がインライン化されている場合はどうですか?
    • どうget() = 4; get() = 3.2ですか?タイプが異なるためにint、そのシーケンスを並べ替えることができますか?float
4

1 に答える 1

5

std::aligned_storageの一部です<type_traits>。そのヘッダー ファイルの残りのほとんどの住民と同様に、これは一部の typedef の単なるホルダーであり、データ型として使用するためのものではありません。その仕事は、サイズとアライメントを取り、それらの特性を持つPODタイプにすることです.

std::aligned_storage<Len, Align>直接使用することはできません。変換された型である を使用する必要があります。これは、「サイズが最大で、アラインメントが の約数であるstd::aligned_storage<Len, Align>::typeオブジェクトの初期化されていないストレージとして使用するのに適した POD 型」です。(デフォルトは、以上の有効なアラインメントの最大値です。)LenAlignAlignLen

C++ 標準が示すように、通常、 によって返される型は、アラインメント指定子std::aligned_storageを持つ (指定されたサイズの)配列になります。unsigned char文字型は他の型に別名を付ける可能性があるため、「厳密な別名なし」ルールを回避します。

したがって、次のようなことができます。

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)...);
}
于 2013-10-07T05:46:58.083 に答える