一つの問題からC++におけるコンストラクタ呼び出しコンストラクタ


#include 
#include 
using namespace std;

struct CLS
{
    int m_i;
    CLS( int i ) : m_i(i){}
    CLS()
    {
        CLS(0);
    }
};
int main()
{
    CLS obj;
    cout << obj.m_i << endl;

    system("PAUSE");
    return 0;
}

印刷結果は不定で、0とは限らない
コードの奇妙な点は、コンストラクション関数で自分のもう一つのコンストラクション関数が呼び出されていることです.オブジェクトを定義すると、1)メモリを割り当てる(非静的データメンバーは初期化されていない)2)コンストラクション関数を呼び出す(コンストラクション関数の本来の意味は非静的データメンバーを初期化することです)上のコードではCLS objが明らかになっています.ここでobjにメモリが割り当てられ、デフォルトコンストラクション関数が呼び出されたが、デフォルトコンストラクション関数はまだ実行されていないのに、別のコンストラクション関数が呼び出された.これは、CLS(int)コンストラクション関数を呼び出し、この匿名の一時オブジェクト自身のデータメンバーm_を生成することに相当する.i初期化は0である.しかしobjのデータメンバーは初期化されていない.そしてobjのm_iは初期化されていないため,その値も不確定であるここから,1)c++では,コンストラクタがデフォルトパラメータを許容するため,このコンストラクタがコンストラクタを呼び出してコードを再利用する必要が大幅に減少する2)一方のコンストラクタのために別のコンストラクタのコードを再利用するだけでは,コンストラクション関数の共通部分を抽出して1つのメンバー関数(privateとして推奨)を定義し、このコードを必要とするコンストラクション関数ごとにその関数を呼び出すことができます3)たまにクラスのコンストラクション関数で別のコンストラクション関数を呼び出すことを望んでいます.コンストラクション関数で別のコンストラクション関数を呼び出す鍵は、新しいメモリを割り当てるのではなく、2番目のコンストラクション関数を最初に割り当てたメモリで実行することです.これは、標準ライブラリのplacement newで行うことができます.
まず、標準ライブラリのplacement newの定義を見てみましょう.
inline void *__cdecl operator new(size_t, void *_P)
{
    return (_P); 
} 

新しいメモリが割り当てられていないことがわかります.
正しい方法:
struct CLS
{
    int m_i;
    CLS( int i ) : m_i(i){}
    CLS()
    {
        new (this)CLS(0);
    }
};