5

次のクラステンプレートがあるとします。

template<typename T>
struct Wrapper {
  T* t_;
  static void check() {
    static_assert(sizeof(Wrapper<T> == sizeof(T*), "Illegal assumption");
  }
};

C99標準とC++03標準を調べましたが、で表されている仮定の保証が見つかりませんstatic_assert。いくつかのコンパイラオプションを使用して、Visual C ++ 2008および2010(32ビット)およびLinux(64ビット)のgccで試してみたところ、仮定が確認されました。

私の質問は:

  • 私の仮定は、Visual C ++ 2008/2010/11(Windows)にとって妥当ですか?
  • gcc 4. *(Linux)の場合?
  • コンパイラフラグの任意の組み合わせについて?
  • この仮定が当てはまらないコンパイラ/プラットフォームを知っていますか?

コンパイラは、たとえばデバッグ目的で、構造体にパディングを追加する可能性があると思います。しかし、実際にそれを行うコンパイラはありますか?

編集:あなたがここで尋ねたように、私は達成したいことです:
私は次の署名を持つメンバー関数を持っています:

Someclass* OtherClass::fn();

このように署名を変更したい:

Wrapper<Someclass> OtherClass::fn();

このラッパーは、スマートポインターのように機能します。つまり、ポインターの存続期間を考慮し、スコープ外になると解放します。関数はdllの境界を越えて呼び出されるので、戻り値(ダムポインターだけでなく、具体的なタイプになりました)がすべての状況(つまり、コンパイラー設定など)でポインターと同じサイズであることを確認したいと思います。だろう。計画/希望は、デバッグ/リリースアプリケーション/dllビルドのすべての組み合わせをサポートすることです。
あなたが尋ねるかもしれませんが:いいえ、私はブーストをdllユーザーに公開したくないので、boost :: shared_ptr <>、std :: shared_ptr <>、std ::unique_ptr<>などを使用することはできません。まだC++11をサポートしていません。

4

3 に答える 3

3

それを想定したいが、コンパイル時のチェックがある場合は、先に進んでください。おそらく、これを行うことでいくつかのメリットが得られます。

パディングについては何も保証されていませんが、通常、パディングは、型の配列が配列のすべてのメンバー(および構造体のすべてのメンバー)を適切に整列させるために整列を取得するために使用されます。ネイティブポインタは通常、整列するのに適切なサイズであるため、パディングは必要ありませんが、それが保証されるわけではありません。

これは、gccで確認できるものではありません。コンパイラだけでなく、ターゲットアーキテクチャによっても異なります。

于 2012-05-04T12:25:09.727 に答える
1

標準を調べてみると、 §9.2[class.mem]に2つの興味深いビットが見つかりました。

17/2つの標準レイアウト構造体(第9節)タイプは、同じ数の非静的データメンバーがあり、対応する非静的データメンバー(宣言順)がレイアウト互換タイプ(3.9)である場合、レイアウト互換です。

したがって、structポインタのみを含む2つはレイアウト互換性があります(したがって、このタイプにアサーションが当てはまる場合、すべてのタイプに当てはまります)。

20 / reinterpret_castを使用して適切に変換された標準レイアウト構造体オブジェクトへのポインターは、その初期メンバー(または、そのメンバーがビットフィールドの場合は、それが存在するユニット)を指し、その逆も同様です。[注:したがって、適切な配置を実現するために必要な場合、標準レイアウトの構造体オブジェクト内に名前のないパディングが存在する可能性がありますが、最初は存在しません。—エンドノート]

メモでは、構造体の先頭にパディングを含めることはできないことを学びます。


目標によっては、20/で十分な場合があります。これは、これが機能することを意味します。

void check(T* t) {
    Wrapper<T>* w = reinterpret_cast<Wrapper<T>*>(t);
    assert(w->t_ == t);
}
于 2012-05-04T12:43:54.333 に答える
1

ほとんどのコンパイラとフラグでは、あなたの仮定は妥当だと思います。

どのTについても、コンパイラーはTの配列を作成できますが、これは連続している必要があるため、パディングなしで作成できる必要があります。そのため、構造体に挿入するパディングは完全にオプションであり、必須のものではありません。

一方、CまたはC ++標準のいずれも、あなたが求めているものを保証するものではないと私は合理的に確信しています。それについての保証に最も近いのは、C ++では標準のレイアウト構造であり、C ++コンパイラがCコンパイラと同じようにフィールドをレイアウトするように制限しているため、メンバーは最初にパディングなしで昇順である必要があります-ただし、メンバー間および/または最後のメンバーの後のパディングは引き続き許可されます。

結論:最初のメンバーへのポインターがある場合は、構造体へのポインターに安全に変換できます(またはその逆)。一方の配列を作成し、もう一方の配列であるかのようにインデックスを作成するなどの操作を行う場合は、自分で行う必要があります。動作する可能性は非常に高いですが、標準では機能しないと確信しています。それを保証します。

于 2012-05-04T12:44:56.517 に答える