C ++でビットフィールド構造体を初期化する最良の方法は何ですか?
-
03-07-2019 - |
質問
C ++には、匿名のビットフィールド構造体を含むクラスがあります。すべてのフィールドを手動で書き出すことなく、ゼロに初期化したい。
3つの場所に初期化を配置することを想像できます。
- ビットフィールドにコンストラクターを作成
- 包含クラスのコンストラクターの初期化リストでゼロになります
- 含まれるクラスのコンストラクターの本体をゼロにします
このビットフィールドには多くのフィールドがあり、それらをすべてリストするのではなく、
たとえば、次のコードを参照してください:
class Big {
public:
Big();
// Bitfield struct
struct bflag_struct {
unsigned int field1 : 1;
unsigned int field2 : 2;
unsigned int field3 : 1;
// ...
unsigned int field20 : 1;
// bflag_struct(); <--- Here?
} bflag;
unsigned int integer_member;
Big *pointer_member;
}
Big::Big()
: bflag(), // <--- Can I zero bflag here?
integer_member(0),
pointer_member(NULL)
{
// Or here?
}
これらのいずれかが望ましいですか?それとも私が行方不明になっている何か他のものがありますか?
編集:以下の受け入れられた答えに基づいて(Feruccioによる)私はこの解決策に落ち着きました:
class Big {
// ...
struct bflag_struct {
unsigned int field 1 : 1;
// ...
bflag_struct() { memset(this, 0, sizeof *this); };
}
// ...
}
解決
コンストラクターでいつでもこれを行うことができます:
memset(&bflag, 0, sizeof bflag);
他のヒント
ビットフィールド構造体を、より簡単に0に初期化するものと結合します。
ユニオンを使用できますが、フィールドにアクセスするときに間接レベルが追加されます:
class Big {
union {
struct {
unsigned int field1 : 1;
...
} fields;
unsigned int all_fields;
};
...
};
Big::Big()
: all_fields(0),
...
{
...
}
MSVCは、ユニオン内で匿名の構造体を許可します(たとえば、D3DMATRIX
の<d3d9.h>
の定義を参照)が、これは非標準のC ++拡張機能であり、可能な場合は使用しないでください。
余談ですが、一部のレガシーコードとのインターフェイスにビットフィールドが必要でない限り、使用しないでください。それらは本質的に移植性がなく、非効率的です。
関数のような初期化子(<!> quot;ここでbflagをゼロにできますか?<!> quot;)は、POD構造体を0の値で初期化するのに100%十分です。
この点でコンパイラが破損していることがわからない限り、これらのメンバーの追加の初期化を行うと、メリットがないために2回初期化されます。
編集:「楽しい」だけのために、VS2005、VS2008、GCC 3.4.4、GCC 4.2、およびBorland C ++ 5.5.1でこれを確認しました... Borland C ++ 5.5.1のみが間違っています。
そして、「間違っている」と言うのは、標準の8.5および8.5.1が、関数のような初期化子がPOD構造体をゼロで初期化することを暗示しているように思えるからです。
ZeroMemoryまたはmemsetを使用して、コンストラクターのメモリをゼロにすることができます。