19

コンストラクターと初期化リストの間で実行時間に違いはありますか?(またはコーディングの好みの問題ですか)。頻繁に作成する必要があるオブジェクトのセットがあり、コンストラクターの代わりに初期化リストを使用することでパフォーマンスが向上するかどうかを知りたいです。

クラス A のインスタンスを 100 万個作成し、クラス B の別の 100 万個のインスタンスを作成する場合、どちらを選択するのがよいでしょうか (オブジェクトはネットワーク内で生成されたパケットを表すため、これらの数値が表示されます)。

 class A {
   private:
     int a, b;

   public:
     A(int a_var, int b_var):a(a_var), b(b_var) {}; 
 };

 class B {
   private:
     int a, b;

   public:
     B(int a_var, int b_var) {
        a = a_var;
        b = b_var;
     }
};

コンストラクターのいずれかがプリミティブ型の他のコンストラクターよりも高速である場合 (例のように)、a と b を型に置き換えると高速になりますか?

タイプ例:

 class AType {
   private:
     string a, b;

   public:
     AType(string a_var, string b_var):a(a_var), b(b_var) {}; 
};
4

5 に答える 5

16

違いは、自明なデフォルト コンストラクターを持たない型の場合です。これは、クラスのコンパイラーによって呼び出されますB。あなたのクラスBは以下と同等です:

 class B {
   private:
     SleepyInt a, b;

   public:
     // takes at least 20s
     B(int a_var, int b_var) : a(), b()
     //                      ^^^^^^^^^^ 
     {
        a = a_var;
        b = b_var;
     }
  };

初期化リストにメンバー変数または基本クラスのコンストラクターを配置しない場合、デフォルトのコンストラクターが呼び出されます。int基本型です-そのデフォルトのコンストラクターは何もかかりません-そのため、例に違いはありませんが、より複雑な型の場合、コンストラクター+代入は構築するだけでなくコストがかかる場合があります。

違いを説明するための面白い例:

class SleepyInt {
public:
  SleepyInt () { 
    std::this_thread::sleep_for(std::chrono::milliseconds( 10000 ));  
  }
  SleepyInt (int i) {}
  SleepyInt & operator = (int i) { return *this; }
};

class A {
   private:
     SleepyInt a, b;

   public:
     A(int a_var, int b_var):a(a_var), b(b_var) {}; 
 };

 class B {
   private:
     SleepyInt a, b;

   public:
     // takes at least 20s
     B(int a_var, int b_var) {
        a = a_var;
        b = b_var;
     }
};
于 2012-11-03T22:53:15.740 に答える
9

コンストラクターでの割り当てではなく、初期化リストを使用することは一般的に受け入れられている方法であり、それには非常に正当な理由があります。

初期化リストは、POD(プレーンオールドデータ)とユーザー定義型の両方を初期化するために使用できます。PODタイプを初期化する場合、効果は代入演算子とまったく同じです。つまり、PODタイプのコンストラクターでの初期化リストまたは代入の間にパフォーマンスの違いはありません。

非PODタイプを検討すると、物事はより興味深いものになります。コンストラクターが呼び出される前に、親クラスのコンストラクターが呼び出され、次に含まれているメンバーが呼び出されます。デフォルトでは、引数なしのコンストラクターが呼び出されます。初期化リストを使用して、呼び出すコンストラクターを選択できます。

したがって、質問に答えるために、パフォーマンスの違いがありますが、それは非PODタイプを初期化する場合のみです。

于 2012-11-03T23:29:03.077 に答える
4

メンバーが多かれ少なかれ複雑な型である場合、割り当ての初期化により、最初にデフォルトのコンストラクターが呼び出され、次にが呼び出されますoperator=。これには時間がかかる場合があります。

于 2012-11-03T22:45:41.750 に答える
2

初期化リストは、有益な参照型、メンバー クラス オブジェクト、または const メンバーです。そうしないと、さらに時間がかかります。

私のテストコードを見てください:

#include <iostream>
#include <ctime>

using namespace std;

class A{
    int a;
public:
    A(int a_):a(a_){}
};

class B{
    int b;
public:
    B(){
    }

    B(int b_){
        b=b_;
    }
};

class C{
    B b;
public:
    C(int c_):b(c_){
    }
};

class D{
    B b;
public:
    D(int d_){
        b=d_;
    }
};

int main()
{
    clock_t start1[10], start2[10], end1[10], end2[10];
    for(int j=0;j<10;j++){
        start1[j]=clock();
        for(int i=0;i<100000;i++){   
            A *newA=new A(i);
            delete newA;
        }
        end1[j]=clock();
        start2[j]=clock();
        for(int i=0;i<100000;i++){   
            B *newB=new B(i);
            delete newB;
        }
        end2[j]=clock();
    }
    double avg1=0, avg2=0;
    for(int i=0;i<10;i++){
        avg1+=(end1[i]-start1[i]);
        avg2+=(end2[i]-start2[i]);
    }
    cout << avg1/avg2 << endl;

    for(int j=0;j<10;j++){
        start1[j]=clock();
        for(int i=0;i<100000;i++){   
            C *newC=new C(i);
            delete newC;
        }
        end1[j]=clock();
        start2[j]=clock();
        for(int i=0;i<100000;i++){   
            D *newD=new D(i);
            delete newD;
        }
        end2[j]=clock();
    }
    avg1=avg2=0;
    for(int i=0;i<10;i++){
        avg1+=(end1[i]-start1[i]);
        avg2+=(end2[i]-start2[i]);
    }
    cout << avg1/avg2 << endl;

    system("pause");
    return 0;
}



次のような出力例:

1.02391
0.934741

于 2013-09-02T13:36:54.657 に答える
2

型が組み込み/組み込み型の場合、パフォーマンスの向上はありません。

それは言った:

結論: 他のすべての条件が同じであれば、代入ではなく初期化リストを使用すると、コードがより高速に実行されます。

于 2012-11-03T22:48:03.770 に答える