11

次のコードが segfaults になる明白な理由はありますか?

#include <vector>
#include <emmintrin.h>

struct point {
    __m128i v;

  point() {
    v = _mm_setr_epi32(0, 0, 0, 0);
  }
};

int main(int argc, char *argv[])
{
  std::vector<point> a(3);
}

ありがとう

編集: Linux/i686 で g++ 4.5.0 を使用しています。ここで何をしているのかわからないかもしれませんが、次の segfaults でさえ

int main(int argc, char *argv[])
{
  point *p = new point();
}

私はそれがアライメントの問題であるに違いないと本当に思います。

4

4 に答える 4

11

v適切に配置されていない場合、明らかに間違っている可能性があります。

ただし、 によって動的に割り当てられるvectorため、スタックのミスアライメントの問題は発生しません。

ただし、phoojiが正しく指摘しているように、「テンプレート」または「プロトタイプ」の値がstd::vectorコンストラクターに渡され、ベクターのすべての要素にコピーされます。std::vector::vectorスタックに配置されるのはこのパラメータであり、ずれている可能性があります。

一部のコンパイラには、関数内のスタック アラインメントを制御するためのプラグマがあります (基本的に、コンパイラは、すべてのローカルを適切にアラインするために、必要に応じて余分なスペースを浪費します)。

Microsoft のドキュメントによると、Visual C++ 2010 は SSE タイプに対して 8 バイトのスタック アラインメントを自動的に設定する必要があり、Visual C++ 2003 以降はそうしています。

gccについてはわかりません。


C++0x では、new point()アラインされていないストレージを返すことは重大な違反です。 [basic.stc.dynamic.allocation]言います(ドラフトn3225からの文言):

割り振り機能は、要求された量のストレージを割り振ろうとします。成功した場合は、バイト単位の長さが要求されたサイズと少なくとも同じ大きさのストレージのブロックの開始アドレスを返す必要があります。割り当て関数から戻ったときに、割り当てられたストレージの内容に制約はありません。連続する割り当て関数の呼び出しによって割り当てられるストレージの順序、連続性、および初期値は規定されていません。返されるポインタは、基本的なアラインメント要件 (3.11) を持つ完全なオブジェクト型のポインタに変換できるように適切にアラインされ、割り当てられたストレージ内のオブジェクトまたは配列にアクセスするために使用されます (ストレージが明示的に割り当て解除されるまで)。対応する割り当て解除関数への呼び出し)。

そして、次の[basic.align]ように述べています。

さらに、要求されたアラインメントを受け入れることができない動的ストレージの実行時割り当ての要求は、割り当ての失敗として扱われます。

これが修正される可能性のある gcc の新しいバージョンを試してみてください。

于 2011-03-07T05:39:11.000 に答える
3

使用vectorしているコンストラクターは、実際には次のように定義されています。

explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );

(例: http://www.cplusplus.com/reference/stl/vector/vector/を参照)。

つまり、1 つの要素がデフォルトで構築され (つまり、コンストラクターを呼び出したときのデフォルトのパラメーター値)、残りの要素は最初の要素をコピーして作成されます。point私の推測では、値の (非) コピーを適切に処理するためのコピー コンストラクターが必要__m128iです。

更新: Visual Studio 2010 (v. 10.0.30319.1) でコードをビルドしようとすると、次のビルド エラーが発生します。

error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned c:\program files\microsoft visual studio 10.0\vc\include\vector 870 1   meh

これは、これがアラインメントの問題であるという点で Ben が正しいことを示唆しています。

于 2011-03-07T05:21:10.793 に答える
1

コンパイラの STL 実装でデフォルト アロケータによって割り当てられるメモリがアラインされていない可能性があります。これは、特定のプラットフォームとコンパイラ ベンダーによって異なります。

通常、デフォルトのアロケーターは operatorを使用しますがnew、これは通常、ワード サイズ (32 ビットまたは 64 ビット) を超えるアライメントを保証しません。この問題を解決するには、 を使用するカスタム アロケータを実装する必要がある場合があります_aligned_malloc

また、単純な修正 (満足のいくものではありませんが) は、値をローカル__m128i変数に代入し、非整列命令を使用してその変数を構造体にコピーすることです。例:

struct point {
    __m128i v;
    point() {
        __m128i temp = _mm_setr_epi32(0, 0, 0, 0);
        _mm_storeu_si128(&v, temp);
    }
};
于 2011-03-07T05:26:43.547 に答える
1

SSE 組み込み関数は、メモリ内で 16 バイトにアラインされている必要があります。をスタックに割り当てる__m128と、コンパイラが自動的にこれらを正しく整列させるため、問題はありません。動的メモリ割り当てを処理するのデフォルト アロケータはstd::vector<>、アラインされた割り当てを生成しません。

于 2011-03-07T05:39:01.443 に答える