web-dev-qa-db-ja.com

C ++ゼロ初期化

クラスのメンバーが http://en.cppreference.com/w/cpp/language/zero_initialization に従ってゼロ初期化されるタイミングと理由を理解するのに問題があります。

次のテストプログラムを検討してください。

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

class MyTest {
private:
    const static unsigned int dimension = 8;
    void (* myFunctions [dimension])();

public: 
    MyTest() {}

    void print() { 
        for(unsigned int i=0; i < MyTest::dimension; i++) {
            printf("myFunctions[%d] = %p\n", i, this->myFunctions[i]);
        }   
    }
};


int main() {
    //We declare and initialize an object on the stack 
    MyTest testObj = {};
    testObj.print();

    return 0;
}

シグネチャ「void functionname()」の8つの関数ポインターの配列を持つクラスを宣言しています。 mainのクラスのオブジェクトをMyTest testObj = {};またはMyTest testObj;として宣言および初期化するとき、ゼロで初期化されることを期待しました。つまり、すべてのポインターはNULLポインターです。

ただし、g++ -m32 -o test -std=c++14 test.cpp && testマシンを使用してWindows 10マシンでg ++ 5.3.0でコンパイルすると、出力が得られます。

myFunctions[0] = 76dd6b7d
myFunctions[1] = 00401950
myFunctions[2] = 0061ff94
myFunctions[3] = 004019ab
myFunctions[4] = 00401950
myFunctions[5] = 00000000
myFunctions[6] = 003cf000
myFunctions[7] = 00400080

スタックの初期化されていない値のように見えます。

オブジェクトの宣言をmainの外(グローバル変数として)に移動すると、すべてのゼロが再び出力されます。

Cppreferenceを正しく理解している場合、これは静的なストレージ期間で変数があり、ゼロで初期化されているためです。クラスのすべての非静的データメンバー(つまり、myFunctions)配列をゼロで初期化することで、クラスタイプを初期化します。配列は、そのすべての要素をゼロで初期化することによって初期化されます。これは、私の関数ポインターの場合、nullポインターです。

MyTest testObj = {};で宣言すると、スタックのオブジェクトがゼロで初期化されないのはなぜですか?

21

以下

MyTest testObj = {};

は、notMyTestのゼロ初期化ですが、デフォルトのコンストラクターを呼び出しているだけです。 cppreferenceページで、理由を説明します(私のものを強調):

値の初期化シーケンスの一部として、非クラス型、およびコンストラクターを持たない値で初期化されたクラス型のメンバーの要素の値の初期化を含む初期化子が提供されていない集合体。

MyTestはクラス型で、aにはコンストラクターがあります。


コンストラクターの定義

MyTest() = default;

代わりに、オブジェクトをzero-initializeします。

以下の関連する標準引用符(強調鉱山)。

[dcl.init#6] から:

タイプTのオブジェクトの値を初期化するには、次のことを意味します。

  • tが(おそらくcv修飾された)クラス型であり、デフォルトコンストラクター([class.ctor])がないか、ユーザー提供または削除されるデフォルトコンストラクターの場合、オブジェクトはデフォルトで初期化されます。

  • Tが(おそらくcv修飾)ユーザー提供または削除されたデフォルトコンストラクターのないクラスタイプの場合、オブジェクトはゼロで初期化され、デフォルトの初期化のセマンティック制約がチェックされ、Tに重要なデフォルトコンストラクターがある場合、オブジェクトはデフォルトで初期化されます。

  • ...

[dcl.init.list] から:

タイプTのオブジェクトまたは参照のリスト初期化は、次のように定義されます。

  • ...

  • それ以外の場合、初期化子リストに要素がなく、Tがデフォルトのコンストラクターを持つクラス型である場合、オブジェクトは値で初期化されます。

30
Vittorio Romeo