💭

c++らしい構造体の定義と初期化

2025/02/01に公開
2

最近以下のC言語っぽい構造体の定義とその初期化をどうやってもっと C++ っぽくできるかっていう問題に出会いました。

typedef struct MyStruct
{
    int a;
    double b;
    CustomType c;
} MyStruct;

MyStruct myStruct;
memset(&myStruct, 0, sizeof(MyStruct)); // メンバを0で初期化

構造体の定義

構造体の定義自体はC言語でもC++でも以下になります。

struct MyStruct
{
    int a;
    double b;
    CustomType c;
};

でもこれだけだと、C言語の場合は、MyStructは構造体専用のネームスペースに追加されるだけなので、構造体のインスタンスを作る時に、以下のように毎回structを付けないといけなくなります。

struct MyStruct myStruct;

これを避けるために、以下のようにtypedefを使って、MyStructをグローバルのネームスペースにも追加します。

typedef struct MyStruct MyStruct;

これを定義と一緒に書くと以下の定義になります。

typedef struct MyStruct
{
    int a;
    double b;
    CustomType c;
} MyStruct;

C++の場合も、構造体専用のネームスペースも一応存在していますが、構造体専用のネームスペースに追加すると自動的にグローバルのネームスペースにも追加されるため、typedefを使う必要がないです。
typedefを使うと、既にグローバルのネームスペースに定義されているものを再定義することになるので、なるべく避けたいと思っています。ただ、typedefで既に定義されている型に再定義することは許されています。(dcl.typedef)そのおかげで、上記のC言語の定義でも問題ないです。

つまりC++では、構造体の定義は以下で十分です。

struct MyStruct
{
    int a;
    double b;
    CustomType c;
};

初期値で初期化

C言語では、以下のようにメンバー変数を1つずつ初期化できます。

MyStruct myStruct = { .a = 0, .b = 0, .c = 0 };

でもメンバー変数が多いせいで全部1つずつ指定したくない場合と、全部同じ値で初期化したい場合は、以下のmemsetでの初期化をよく見かけます。

MyStruct myStruct;
memset(&myStruct, 0, sizeof(MyStruct));

これをC++っぽく書こうとしたくて、以下のように初期化しているのをたまに見かけます。

MyStruct myStruct{0};
MyStruct myStruct = {0};

確かにそれっぽく見えますが、これはmemsetの初期化と違う意味になります。

最初のメンバー変数だけが0で初期化されて、他のメンバー変数はデフォルト初期値で初期化されます。double型のbのデフォルト初期値が0.0なので、結果的に変わらないですが、CustomTypeの初期値が0以外の値の場合は、話が変わってきます。

memsetでの初期化と同じことがしたい場合は、以下のように全メンバーに値を指定するしかないです。

MyStruct myStruct{0, 0, 0};

でもそもそもmemsetでメンバー変数の型をガン無視で構造体のメモリを0で上書きするような強引な初期化のやり方自体がC++らしくないのです。

C++はカスタム型を自由自在に定義できるし、初期値も型によって違ったりするため、C++的に正しい初期化のやり方は以下になります。

MyStruct myStruct{};

これだと、全メンバーが各々のデフォルト初期値で初期化されます。これが一番C++らしい初期化です。


|cpp記事一覧へのリンク|

Discussion

齊藤敦志齊藤敦志

C++の場合も、構造体専用のネームスペースも一応存在していて、上記のC言語の定義でも問題ないですが、

いいえ。

名前空間が異なるから出来るのではなく、再定義を許すという規則によって許されます。

スペース・ソルバ株式会社スペース・ソルバ株式会社

コメントありがとうございます。すみません元の文章では↓の2つの点があいまいに混ざった表現となっていたと思います。

  1. c++の構造体定義ではtypedefをつける必要がなくなっていること
  2. typedef structと記述した場合にどの様に解釈されるのか

もともと意識していたのは(1)の点のみで、指摘いただいた観点が不足していました。
リンクいただいた内容も踏まえて記事に反映してみました。

ありがとうございます。