8

function を宣言するとしますfoo(int arg1, int arg2 = 0, int arg3 = 0, int arg4 = 0)。最後の 3 つの引数はときどき (存在する場合) だけ指定され、ほとんどの場合、関数は として呼び出されfoo(some_int)ます。foo(int arg1)代わりに関数を として宣言し、実際に必要な場合は他の引数を渡すための別のソリューションを使用することで、パフォーマンスを向上させることができますか?

言い換えれば、宣言されているが指定されていないデフォルト引数は関数呼び出しを遅くしますか?

この場合の関数はオブジェクトのコンストラクターですが、それは一般的な質問です。

4

2 に答える 2

5

(よろしければ、最後に結論だけをお読みください)

これをテストするためにベンチマークを行いました。最初に、この短いプログラムを約 10 回実行しました。

#include <iostream>
#include <ctime>

using namespace std;

int returnMe(int me)
{
    return me;
}


int main()
{
   float begin = (float)clock();
   for(int i = 0; i < 100000000; i++)
   {
       int me = returnMe(i);
   }
   printf("\nTime: %f\n", begin);
   printf("\nTime: %f\n", (float)clock());

   return 0;
}

これは基本的に関数returnMeを 1 億回実行し、その実行にかかった時間を教えてくれます。値の範囲は 280 ミリ秒から 318 ミリ秒でした。次に、このプログラムを実行しました。

#include <iostream>
#include <ctime>

using namespace std;

int returnMe(int me, int me87 = 0, int m8e = 0, int m5e = 0, int m34e = 0,int m1e = 0,int me234 = 0,int me332 = 0,int me43 = 0,int me34 = 0,int me3 = 0,int me2 = 0,int me1 = 0)
{
    return me;
}


int main()
{
   float begin = (float)clock();
   for(int i = 0; i < 100000000; i++)
   {
       int me = returnMe(i);
   }
   printf("\nTime: %f\n", begin);
   printf("\nTime: %f\n", (float)clock());

   return 0;
}

約 10 回、値は現在 584 ミリ秒から 624 ミリ秒の範囲でした。

結論:はい、関数呼び出しが遅くなりますが、ごくわずかです。他の引数をオブジェクトに渡すための別の関数を作成するか、別のコンストラクターを使用すると、パフォーマンスが向上しますが、コードを追加する価値はありますか?

それを解決する別の方法があり、Box2D で使用されます。これは基本的に、デフォルト引数用に別の構造体を作成し、そのインスタンスへのポインターを渡します。そうすれば、余分な引数を設定する必要がない場合、渡されるパフォーマンスを低下させる唯一の「ガベージ引数」は 1 つの nullpointer であり、それほど悪くはありません。いくつかのデフォルト値を指定したい場合は、スタックでその構造体のインスタンスを作成し、必要な値を入力してから、そのアドレスを関数に渡します。簡単、エレガント、効率的。

ただし、パフォーマンスを節約するために提案された両方のソリューション (追加の関数と構造体ポインターを渡す) には、追加のコードが必要です。関数がめったに呼び出されず、余分な引数がそれほど多くない場合、保存されたパフォーマンスがまったく違いをもたらさない可能性があり、その場合は時間の価値がありません。必要な場合にのみ最適化してください。12 個のデフォルト引数を追加したことを思い出してください。関数の呼び出し時間は 2 倍にもなりませんでした。

======== 編集: 本格的なテストのボーナス。

したがって、最初の 2 つのテストは単純なコンパイル コマンドで実行されましたg++ test.cpp -o test.exe。多数のコメントで指摘されているように、これは -O0 の最適化レベルを意味します。-O3 でテストすると、どのような結果が得られるでしょうか?

でコンパイルしてテストを繰り返しg++ test.cpp -o test.exe -O3ましたが、プログラムが 1 ~ 2 ミリ秒未満で完了することがわかりました。反復を 1 兆回、次に 100 兆回に上げようとしましたが、同じ結果でした。したがって、g++ はおそらく、使用しない変数を宣言していることを認識していたため、 への呼び出しをスキップし、おそらくreturnMeループ全体をスキップしていると考えました。

有用な結果を得るために、実際の機能を に追加してreturnMe、最適化されていないことを確認しました。使用したプログラムは次のとおりです。

#include <iostream>
#include <ctime>

using namespace std;

long long signed int bar = 0;

int returnMe(int me)
{
    bar -= me;
    return me;
}


int main()
{
   float begin = (float)clock();
   for(int i = 0; i < 1000000000; i++)
   {
       int me = returnMe(i);
       bar -= me * 2;
   }
   printf("\nTime: %f\n", begin);
   printf("\nTime: %f\n", (float)clock());
   printf("Bar: %i\n", bar);

   return 0;
}

#include <iostream>
#include <ctime>

using namespace std;

long long signed int bar = 0;

int returnMe(int me, int me87 = 0, int m8e = 0, int m5e = 0, int m34e = 0,int m1e = 0,int me234 = 0,int me332 = 0,int me43 = 0,int me34 = 0,int me3 = 0,int me2 = 0,int me1 = 0)
{
    bar -= me;
    return me;
}

int main()
{
   float begin = (float)clock();
   for(int i = 0; i < 1000000000; i++)
   {
       int me = returnMe(i);
       bar -= me * 2;
   }
   printf("\nTime: %f\n", begin);
   printf("\nTime: %f\n", (float)clock());
   printf("Bar: %i\n", bar);

   return 0;
}

結果:

最初のプログラム: 653 ~ 686 ms

2 番目のプログラム: 652 ~ 735 ms

予想どおり、2 番目のプログラムは最初のプログラムよりもまだ遅いですが、違いはそれほど目立たなくなりました。

于 2014-06-18T12:32:09.437 に答える