2009-07-01 6 views

答えて

217

構造体を初期化していない場合はnullではありません。

Snapshot s; // receives no initialization 
Snapshot s = {}; // value initializes all members 

2番目のメンバーはすべてゼロになり、1番目のメンバーはすべて不特定の値になります。それは再帰的であることに注意してください:

struct Parent { Snapshot s; }; 
Parent p; // receives no initialization 
Parent p = {}; // value initializes all members 

p.s.{x,y} 0になります。構造体にコンストラクタがある場合は、これらの集約初期化子リストを使用することはできません。これは、値の初期化です:そのような場合は、

struct Snapshot { 
    int x; 
    double y; 
    Snapshot():x(0),y(0) { } 
    // other ctors/functions... 
}; 

は、あなたがそのタイプの無視、それらを初期化するためにx(), y()を使用することができます0に注意することはxとyの両方を初期化しますそれらのコンストラクタに適切なinitalizationを追加する必要があります通常は適切な初期値を返します(intは0、doubleは0.0、ユーザーが定義したコンストラクタを持つユーザー定義型のデフォルトコンストラクタを呼び出します)。これは特に、構造体がテンプレートの場合に重要です。

+1

これは私のコンパイラで多くの警告を生成します。 –

+1

Roger:イニシャライザで名前付き構造体を使用しようとすると、それは私が行うことであり、VC 2012では警告が表示されません:Snapshot s = Snapshot(); – Kit10

+0

@Johannes Schaub - litb Will 'Snapshot s = {}; '非PODメンバーのために働く(ゼロにするため)? – ontherocks

36

いいえ、デフォルトでは0ではありません。すべての値または0にデフォルト設定することを確保するための最も簡単な方法は、コンストラクタ

Snapshot() : x(0), y(0) { 
} 

を定義することですこれは、スナップショットのすべての使用が値を初期化していることが保証されます。

+24

構造体がコンストラクタを持っているため、構造体はもはやPOD型ではないという欠点があります。それは、一時ファイルに書き込むなどのいくつかの操作が中断されます。 – finnw

+15

@finnw:C++ 11ではこれを修正しましたが、構造体はPODではありませんが、 "標準レイアウト"です。 –

3

正しい答えは、その値が定義されていないと思います。しばしば、デバッグバージョンのコードを実行するときに0に初期化されます。これは通常、リリースバージョンを実行している場合には当てはまりません。

+2

実際には、デバッグバージョンはメモリ内のそれらの場所に既に '0'を持っています。これは初期化と同じではありません! –

16

一般に、これはPOD(本質的にC構造体)であるので

int x; // 0 
int y = 42; // 42 
struct { int a, b; } foo; // 0, 0 

void foo() { 
    struct { int a, b; } bar; // undefined 
    static struct { int c, d; } quux; // 0, 0 
} 
+1

これは本当に安全な仮定ではありません。 – Hasturkun

+17

スタティックストレージデュレーションオブジェクトは常にゼロに初期化されます - http://stackoverflow.com/questions/60653/is-global-memory-initialized-in-c/を参照してください。 60707#60707標準からの引用のために。これが良いスタイルかどうかは別の問題です。 – bdonlan

4

:ただし、構造体は、関数にファイルスコープまたは静的として宣言/ /(ちょうどそれらのスコープの全ての他の変数のような)を0に初期化されます

Snapshot s; 
memset(&s, 0, sizeof (s)); 

または同様

Snapshot *sp = new Snapshot; 
memset(sp, 0, sizeof (*sp)); 

私がこれまでにかかわらず、C++プログラムでcalloc()を使用するように行かないだろう。それをCの方法を初期化するにはほとんど害があります。

+5

携帯用ではありません。 0ポインタは0以外の値を持つことができます。 –

+1

@Sergey、はい、この構造体にはポインタが含まれていません。 – finnw

+3

同じことが二重にも適用されます。全ビット・ゼロは必ずしも0.0ではない。ただし、IEEE754の倍数があるかどうかを確認することができます。その場合は、動作する必要があります。 – MSalters

7

C++では、引数のないコンストラクタを使用します。Cでは、コンストラクタを持つことができませんので、memsetかのいずれかを使用 - 興味深いソリューション - 指定された初期化子:あなたはまた、あなたがCでのmemsetを使用しないでください

Snapshot s = {}; 

を書くことができPODで

struct Snapshot s = { .x = 0.0, .y = 0.0 }; 
+0

私はこれがCであり、C++ではないと信じています。一部のC++コンパイラではコンパイルに失敗します。 CygwinやMinGWでコンパイルエラーが発生しました。 – jww

11

を++ memsetには構造体に非PODがあれば破壊するという欠点があります。あなたの初期化子リストを短縮するために、基本クラスへ

struct init 
{ 
    template <typename T> 
    operator T *() 
    { 
    return new T(); 
    } 
}; 

Snapshot* s = init(); 
+0

[Mr. Vexing Parse氏に気を付ける](http://codepad.org/utBvhcQ5) –

+0

@LightnessRacesinOrbit oh wat? – Andy

+0

@Andy Most Vexing Parseは、通常のctorsのように見えるものを変えます。 'SomeType foo();'は、他のものでも起こりうる典型的なものですが、関数定義になります(その場合、関数 'foo' 'SomeType')。申し訳ありませんがnecro、誰かがこれを横切ってつまずく場合、私は答えたいと思った。 –

1

移動ポッドメンバー:

またはこのような

struct foo_pod 
{ 
    int x; 
    int y; 
    int z; 
}; 

struct foo : foo_pod 
{ 
    std::string name; 
    foo(std::string name) 
     : foo_pod() 
     , name(name) 
    { 
    } 
}; 

int main() 
{ 
    foo f("bar"); 
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str()); 
} 
関連する問題