web-dev-qa-db-ja.com

非自明なコンストラクターでユニオンを初期化する

メンバーを0に初期化するカスタムコンストラクターを作成する構造があります。古いコンパイラでは、リリースモードでは、memsetを0にしないと、値が初期化されないことがわかりました。

私は今、この構造体を共用体で使用したいのですが、非自明なコンストラクターがあるためエラーが発生します。

したがって、質問1。デフォルトのコンパイラー実装コンストラクターは、構造体のすべてのメンバーがヌルで初期化されることを保証しますか?非自明なコンストラクターは、すべてのメンバーのmemsetを「0」にして、クリーンな構造を確保します。

質問2:コンストラクターを基本構造に指定する必要がある場合、その要素を含むようにユニオンを実装して、初期化された基本要素を0にするにはどうすればよいですか?

53
Superpolock

質問1:デフォルトのコンストラクターは、C++標準に従ってPODメンバーを0に初期化します。以下の引用テキストを参照してください。

質問2:コンストラクターを基本クラスで指定する必要がある場合、そのクラスを共用体の一部にすることはできません。

最後に、ユニオンのコンストラクターを提供できます。

union U 
{
   A a;
   B b;

   U() { memset( this, 0, sizeof( U ) ); }
};

Q1の場合:

C++ 03、12.1コンストラクターから、ページ190

暗黙的に定義されたデフォルトコンストラクターは、空のmem-initializer-list(12.6.2)と空の関数本体を使用して、そのクラスのユーザー作成のデフォルトコンストラクターによって実行されるクラスの初期化セットを実行します。

C++ 03から、8.5初期化子、ページ145

タイプTのオブジェクトをデフォルトで初期化するには、次のことを意味します。

  • tが非PODクラス型(9節)の場合、Tのデフォルトコンストラクターが呼び出されます(Tにアクセス可能なデフォルトコンストラクターがない場合、初期化は不正な形式です)。
  • tが配列型の場合、各要素はデフォルトで初期化されます。
  • それ以外の場合、オブジェクトはゼロで初期化されます

タイプTのオブジェクトをゼロで初期化するとは、次のことを意味します。

  • tがスカラー型(3.9)の場合、オブジェクトはTに変換された値0(ゼロ)に設定されます。
  • Tが非ユニオンクラスタイプである場合、各非静的データメンバーと各ベースクラスサブオブジェクトはゼロで初期化されます;
  • Tがユニオン型の場合、オブジェクトの最初の名前付きデータメンバーはゼロで初期化されます;
  • tが配列型の場合、各要素はゼロで初期化されます。
  • tが参照型の場合、初期化は実行されません。

Q2の場合:

C++ 03、12.1コンストラクターから、ページ190

コンストラクターは、暗黙的に宣言されたデフォルトコンストラクターであり、次の場合に簡単です。

  • そのクラスには仮想関数(10.3)および仮想基本クラス(10.1)がありません。
  • そのクラスのすべての直接ベースクラスには、簡単なコンストラクタがあります。
  • クラス型(またはその配列)であるそのクラスのすべての非静的データメンバについて、そのような各クラスには単純なコンストラクタがあります

C++ 03、9.5ユニオン、pg 162から

ユニオンにはメンバー関数(コンストラクターおよびデストラクターを含む)を含めることができますが、仮想(10.3)関数は含めることができません。ユニオンには基本クラスがありません。ユニオンは基本クラスとして使用されません。非自明なコンストラクター(12.1)、非自明なコピーコンストラクター(12.8)、非自明なデストラクター(12.4)、または非自明なクラスのオブジェクトコピー代入演算子(13.5.3、12.8)は、ユニオンのメンバーにすることも、そのようなオブジェクトの配列にすることもできません

C++ 11で改善された点

Stroustrupによって記述された 彼自身として、これを合法的に行うことができます( WikipediaのC++ 11に関する記事 からそのリンクに到達しました)。

ウィキペディアの例は次のとおりです。

#include <new> // Required for placement 'new'.

struct Point {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
    int x_, y_;
};

union U {
    int z;
    double w;
    Point p; // Illegal in C++03; legal in C++11.
    U() {new(&p) Point();} // Due to the Point member, a constructor
                           // definition is now *required*.
};

Stroustrupはもう少し詳しく説明します。

31
dan-man

AFAIKユニオンメンバーには、コンストラクターまたはデストラクターがない場合があります。

質問1:いいえ、そのような保証はありません。コンストラクターの初期化リストにないPODメンバーはデフォルトで初期化されますが、これはユーザーが定義したコンストラクターであり、初期化リストがあります。コンストラクターを定義しない場合、または初期化子リストと空のボディなしでコンストラクターを定義した場合、PODメンバーは初期化されません。

非PODメンバーは常にデフォルトのコンストラクターを介して構築されます。デフォルトのコンストラクターは、合成された場合、再びPODメンバーを初期化しません。ユニオンメンバにコンストラクタがない場合、ユニオン内の構造体のPODメンバが初期化されないことがほぼ保証されます。

質問2:構造/ユニオンはいつでも初期化できます:

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };
3
unwesen

nwesen の投稿に対するGreg Rogersのコメントで述べたように、ユニオンにコンストラクタ(および必要に応じてデストラクタ)を与えることができます。

struct foo
{
    int a;
    int b;
};

union bar
{
    bar() { memset(this, 0, sizeof(*this)); }

    int a;
    foo f;
};
2
Adam Rosenfield

このようなことはできますか?

class Outer
{
public:
    Outer()
    {
        memset(&inner_, 0, sizeof(inner_));
    }
private:
    union Inner
    {
        int qty_;
        double price_;
    } inner_;
};

...またはこのようなものですか?

union MyUnion
{
    int qty_;
    double price_;
};

void someFunction()
{
    MyUnion u = {0};
}
0
John Dibling