web-dev-qa-db-ja.com

C ++構造体を初期化する適切な方法

このコードには、POD(Plain Old Datastructure)構造体が含まれています(これは、最初に初期化する必要がある他の構造体とPOD変数を持つ基本的なc ++構造体です)。

私が持っているものの1つに基づいて 読み取り 、それはそうです:

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

次のように、すべての値をゼロに初期化する必要があります。

myStruct = new MyStruct();

ただし、構造体が2番目の方法で初期化されると、Valgrindは、それらの変数が使用されると「条件付きジャンプまたは移動は初期化されていない値に依存する」と後で訴えます。ここで私の理解に欠陥がありますか、またはValgrindは誤検知を投げかけていますか?

69
Shadow503

C++では、クラス/構造体は(初期化に関して)同じです。

非POD構造体にもコンストラクタがあり、メンバーを初期化できます。
構造体がPODの場合、初期化子を使用できます。

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

または、デフォルトのコンストラクターを使用できます。

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

Valgrindが文句を言っているのは、それがC++の動作方法だったからです。 (C++がゼロ初期化デフォルト構造でアップグレードされた時期は正確にはわかりません)。最善の策は、オブジェクトを初期化するコンストラクターを追加することです(構造体はコンストラクターとして許可されます)。

補足として:
多くの初心者がinitを重視しています:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

「Most Vexing Parse」をすばやく検索すると、説明よりも優れた説明が得られます。

102
Martin York

あなたが私たちに言ったことから、それはvalgrindで偽陽性であるように見えます。 ()を含むnew構文は、オブジェクトがPODであると仮定して、値を初期化する必要があります。

構造体の一部が実際にはPODではなく、それが予期される初期化を妨げている可能性はありますか? valgrindエラーにフラグを立てる投稿可能なサンプルにコードを単純化できますか?

あるいは、コンパイラが実際にPOD構造の値を初期化しないこともあります。

いずれにせよ、おそらく最も簡単な解決策は、構造体/サブパートに必要なコンストラクターを記述することです。

2
Mark B

私はいくつかのテストコードを書きます:

#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct sc {
    int x;
    string y;
    int* z;
};

int main(int argc, char** argv)
{
   int* r = new int[128];
   for(int i = 0; i < 128; i++ ) {
        r[i] = i+32;
   }
   cout << r[100] << endl;
   delete r;

   sc* a = new sc;
   sc* aa = new sc[2];
   sc* b = new sc();
   sc* ba = new sc[2]();

   cout << "az:" << a->z << endl;
   cout << "bz:" << b->z << endl;
   cout << "a:" << a->x << " y" << a->y << "end" << endl;
   cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
   cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
   cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
}

g ++のコンパイルと実行:

./a.out 
132
az:0x2b0000002a
bz:0
a:854191480 yend
b:0 yend
aa:854190968 yend
ba:0 yend
1
Yadong

これはPOD構造体なので、常に0にmemsetすることができます-これは、フィールドが初期化される最も簡単な方法かもしれません(適切であると仮定)。

0
Scott C Wilson

構造体にあるメンバーを初期化する必要があります。例:

struct MyStruct {
  private:
    int someInt_;
    float someFloat_;

  public:
    MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values

};
0
ralphtheninja