内部的に、生成されたコードについて、次の間に本当に違いがありますか?
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
そして
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
ありがとう...
回答:
これらの値がプリミティブ型であると仮定すると、違いはありません。違いはありません。初期化リストは、デフォルトの初期化に続いて割り当てを使用する代わりに、オブジェクトをメンバーとして持つ場合にのみ違いを生じさせます。初期化リストを使用すると、オブジェクトをその最終値に初期化できます。これは実際には著しく速くなります。
初期化リストを使用して、定数メンバー、参照、および基本クラスを初期化する必要があります
コメントで述べられているように、定数メンバー、参照を初期化し、パラメーターを基本クラスコンストラクターに渡す必要がある場合は、初期化リストを使用する必要があります。
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
例(網羅的ではない)クラス/構造体には参照が含まれています。
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
そして、パラメーターを必要とする基本クラスを初期化する例(デフォルトのコンストラクターなしなど):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
、_data
および_len
アクセスデフォルトコンストラクタなしでクラスの型を持っていますか?
const
、コンストラクターの本体でメンバーを初期化できないことです。初期化リストを使用する必要があります-非const
メンバーは、初期化リストまたはコンストラクターの本体で初期化できます。
はい。最初のケースでは、宣言することができ_capacity
、_data
および_len
定数として:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
const
これらのインスタンス変数の実行時に値を計算する際に、これらのインスタンス変数が適切であることを確認したい場合は、次のように重要です。
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
インスタンスはイニシャライザリストで初期化する必要があります。そうでない場合、基になる型は、パラメータなしのパブリックコンストラクタを提供する必要があります(プリミティブ型はこれを行います)。
このリンクhttp://www.cplusplus.com/forum/articles/17820/は、特にC ++を初めて使用する人にとって、すばらしい説明になると思います。
初期化リストがより効率的である理由は、コンストラクター本体内では割り当てのみが行われ、初期化は行われないためです。したがって、非組み込み型を扱う場合、コンストラクターの本体が入力される前に、そのオブジェクトのデフォルトコンストラクターがすでに呼び出されています。コンストラクタ本体の中で、そのオブジェクトに値を割り当てています。
実際には、これはデフォルトのコンストラクターへの呼び出しと、それに続くコピー代入演算子の呼び出しです。初期化リストを使用すると、コピーコンストラクターを直接呼び出すことができます。これにより、かなり高速になる場合があります(初期化リストはコンストラクターの本体の前にあることを思い出してください)。
実際の違いは、gccコンパイラーがマシンコードを生成してメモリーを配置する方法に要約されます。説明:
const型のメンバーを処理する方法は確かに他にもあります。しかし、生活を楽にするために、gccコンパイラの作成者はいくつかのルールを設定することにしました
基本クラスインスタンスと非静的メンバー変数を初期化する方法は1つしかなく、それは初期化子リストを使用しています。
コンストラクターの初期化子リストでベースまたは非静的メンバー変数を指定しない場合、そのメンバーまたはベースはデフォルトで初期化されます(メンバー/ベースが非PODクラスタイプまたは非PODクラスの配列の場合)タイプ)またはそれ以外の場合は初期化されないままにします。
コンストラクター本体に入ると、すべてのベースまたはメンバーが初期化されるか、初期化されないままになります(つまり、不定の値になります)。コンストラクター本体には、初期化方法に影響を与える機会はありません。
コンストラクター本体のメンバーに新しい値を割り当てることができる場合がありますが、const
メンバーまたはクラスタイプのメンバーに割り当てることができなくなり、参照を再バインドすることはできません。
組み込み型および一部のユーザー定義型の場合、コンストラクター本体での割り当ては、初期化子リストの同じ値で初期化するのとまったく同じ効果がある場合があります。
イニシャライザリストのメンバーまたはベースの名前付けに失敗し、そのエンティティが参照であり、アクセス可能なユーザー宣言のデフォルトコンストラクターがないクラスタイプであり、const
修飾され、PODタイプであるか、PODクラスタイプまたはPODクラスタイプの配列である場合含むconst
修飾体を(直接的または間接的に)、プログラムが悪い形成されています。
コンストラクター内の初期化リストと初期化ステートメントには違いがあります。以下のコードを考えてみましょう:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
MyClassを使用すると、コンストラクターの最初のステートメントが実行される前に、すべてのメンバーが初期化されます。
ただし、MyClass2を使用すると、コンストラクターの最初のステートメントが実行されたときに、すべてのメンバーが初期化されません。
後者の場合、特定のメンバーが初期化される前に、誰かがコンストラクターにコードを追加したときに、回帰問題が発生する可能性があります。
ここで私が他の人がそれを参照するのを見なかった点があります:
class temp{
public:
temp(int var);
};
tempクラスにはデフォルトのctorはありません。次のように別のクラスで使用する場合:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
コードがコンパイルされず、コンパイラーが初期化の方法を認識できないため、コードにはobj
int値を受け取る明示的なctorしかないため、次のようにctorを変更する必要があります。
mainClass(int sth):obj(sth){}
したがって、それはconstと参照だけではありません!