60

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

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

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

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

4

6 に答える 6

52

質問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が参照型の場合、初期化は実行されません。

第2四半期の場合:

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

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

  • そのクラスには仮想関数(10.3)と仮想基本クラス(10.1)がなく、
  • そのクラスのすべての直接基本クラスには、簡単なコンストラクターがあり、
  • クラスタイプ(またはその配列)であるそのクラスのすべての非静的データメンバーの場合、そのような各クラスには簡単なコンストラクターがあります

C ++ 03から、9.5ユニオン、162ページ

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

于 2008-11-26T19:33:20.370 に答える
38

C++11 では状況が改善されました。

Stroustrup 自身が説明したように、合法的にこれを行うことができます( 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 がもう少し詳しく説明します。

于 2015-10-22T20:20:28.070 に答える
2

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

struct foo
{
    int a;
    int b;
};

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

    int a;
    foo f;
};
于 2008-11-26T19:41:16.843 に答える
2

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

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

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

質問 2: 次のように構造体/共用体をいつでも初期化できます。

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };
于 2008-11-26T17:13:50.370 に答える
0

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

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};
}
于 2008-11-26T16:44:37.747 に答える
-3

これを取得するには、コンパイラがC++0xをサポートするのを待つ必要があります。それまで、ごめんなさい。

于 2008-11-26T17:51:40.497 に答える