(よろしければ、最後に結論だけをお読みください)
これをテストするためにベンチマークを行いました。最初に、この短いプログラムを約 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 番目のプログラムは最初のプログラムよりもまだ遅いですが、違いはそれほど目立たなくなりました。