331

以下に示すように、C++ で構造体を初期化することは可能ですか?

struct address {
    int street_no;
    char *street_name;
    char *city;
    char *prov;
    char *postal_code;
};
address temp_address =
    { .city = "Hamilton", .prov = "Ontario" };

ここここのリンクは、このスタイルを C でのみ使用できることを示しています。C ++で実装されていない根本的な技術的な理由はありますか、それともこのスタイルを使用するのは悪い習慣ですか? 構造体が大きく、このスタイルにより、どの値がどのメンバーに割り当てられているかが明確に読みやすくなるため、この初期化方法を使用するのが好きです。

同じ可読性を達成できる他の方法があれば教えてください。

この質問を投稿する前に、次のリンクを参照しました

  1. C/C++ for AIX
  2. 変数による C 構造体の初期化
  3. C++ でのタグによる静的構造の初期化
  4. C++11 の適切な構造体の初期化
4

17 に答える 17

205

各初期化子の値が何であるかを明確にしたい場合は、複数の行に分割し、それぞれにコメントを付けます。

address temp_addres = {
  0,  // street_no
  nullptr,  // street_name
  "Hamilton",  // city
  "Ontario",  // prov
  nullptr,  // postal_code
};
于 2012-07-17T06:03:16.450 に答える
117

私の質問に対して満足のいく結果が得られなかった後(C++ は構造体のタグベースの初期化を実装していないため)、私はここで見つけたトリックを採用しました: Are members of a C++ struct initialized to 0 by default?

あなたにとっては、それを行うことになります:

address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";

これは確かに、最初に望んでいたものに最も近いものです (初期化するフィールド以外のすべてのフィールドをゼロにします)。

于 2012-07-17T06:22:13.407 に答える
19

フィールド識別子は、実際には C 初期化構文です。C++ では、フィールド名なしで正しい順序で値を指定するだけです。残念ながら、これはそれらすべてを指定する必要があることを意味します (実際には、末尾のゼロ値フィールドを省略でき、結果は同じになります):

address temp_address = { 0, 0, "Hamilton", "Ontario", 0 }; 
于 2012-07-17T05:51:55.530 に答える
12

この質問はかなり古いことは知っていますが、constexpr とカリー化を使用して初期化する別の方法を見つけました。

struct mp_struct_t {
    public:
        constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
        constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
        constexpr mp_struct_t another_member(int member) { return {member1, member, member3}; }
        constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }

    int member1, member2, member3;
};

static mp_struct_t a_struct = mp_struct_t{1}
                           .another_member(2)
                           .yet_another_one(3);

このメソッドは、グローバルな静的変数や constexpr 変数に対しても機能します。唯一の欠点は保守性が悪いことです。このメソッドを使用して別のメンバーを初期化可能にする必要があるたびに、すべてのメンバーの初期化メソッドを変更する必要があります。

于 2014-10-03T23:56:42.217 に答える
7

Gui13 のソリューションを単一の初期化ステートメントにパックすることもできます。

struct address {
                 int street_no;
                 char *street_name;
                 char *city;
                 char *prov;
                 char *postal_code;
               };


address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);

免責事項: このスタイルはお勧めしません

于 2012-07-17T09:46:42.950 に答える
5

C++ では実装されていません。(また、char*文字列?そうでないことを願っています)。

通常、非常に多くのパラメーターがある場合、それはかなり深刻なコード臭です。しかし代わりに、単純に構造体の値を初期化してから、各メンバーを割り当ててみませんか?

于 2012-07-17T06:02:34.323 に答える
4

元の構造定義を変更する必要がない、グローバル変数に対してこの方法を見つけました。

struct address {
             int street_no;
             char *street_name;
             char *city;
             char *prov;
             char *postal_code;
           };

次に、元の構造体型から継承された新しい型の変数を宣言し、フィールドの初期化にコンストラクターを使用します。

struct temp_address : address { temp_address() { 
    city = "Hamilton"; 
    prov = "Ontario"; 
} } temp_address;

ただし、Cスタイルほどエレガントではありません...

ローカル変数の場合、コンストラクターの先頭に memset(this, 0, sizeof(*this)) を追加する必要があるため、明らかに悪くはなく、@ gui13 の答えがより適切です。

('temp_address' は 'temp_address' 型の変数ですが、この新しい型は 'address' から継承され、'address' が予期されるすべての場所で使用できることに注意してください。)

于 2016-11-07T10:18:25.790 に答える
2

C++ では、C スタイルの初期化子は、コンパイル時に有効な初期化のみが実行されることを保証できるコンストラクターに置き換えられました (つまり、初期化後、オブジェクト メンバーは一貫しています)。

これは良い習慣ですが、例のように事前初期化が便利な場合があります。OOP は、抽象クラスまたは作成設計パターンによってこれを解決します。

私の意見では、この安全な方法を使用すると単純さが損なわれ、セキュリティのトレードオフが高くつく場合があります。単純なコードは保守性を維持するために洗練された設計を必要としないためです。

別の解決策として、ラムダを使用してマクロを定義し、C スタイルのように初期化を簡素化することをお勧めします。

struct address {
  int street_no;
  const char *street_name;
  const char *city;
  const char *prov;
  const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE

ADDRESS マクロは次のように展開されます。

[] { address _={}; /* definition... */ ; return _; }()

ラムダを作成して呼び出します。マクロ パラメーターもコンマで区切られているため、初期化子を角かっこに入れて次のように呼び出す必要があります。

address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));

一般化されたマクロ初期化子を書くこともできます

#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE

しかし、呼び出しは少し美しくありません

address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));

ただし、一般的な INIT マクロを使用して ADDRESS マクロを簡単に定義できます。

#define ADDRESS(x) INIT(address,x)
于 2016-07-06T11:16:46.740 に答える
1

可能ですが、初期化する構造体が POD (プレーン オールド データ) 構造体である場合に限ります。メソッド、コンストラクター、さらにはデフォルト値を含めることはできません。

于 2015-08-11T19:58:26.930 に答える