[C++]値渡しとポインタ渡しと参照渡しに関する実行速度について
趣味でC++を書いていて、書き方やデザインなど勉強するためにEffective C++ 第3版を買って読んでいます。その中で、値渡しよりconst参照渡しを使おうという項目を読んでいるときに、値渡しとポインタ渡しと参照渡しの実行速度について、気になりました。おそらく参照渡しが早いと思いますが、実際に測定して調べてみました。
使用環境
- Visual Studio Community 2017
- コンパイル時有効になっているバージョン /std:c++latest
使用コード
測定には、std::chronoを使用した簡易的な時間測定クラスを用いて測定しました。
時間測定クラス
#ifndef _TIMEMEASURER_H_
#define _TIMEMEASURER_H_
#include <chrono>
namespace Timer
{
//時間測定クラス
//timerStartメソッドで測定開始
//timerEndメソッドで測定終了
class TimeMeasurer
{
public:
TimeMeasurer() :_isStarted(false) {};
~TimeMeasurer() {};
//測定開始メソッド
void timerStart();
//測定終了メソッド
void timerEnd();
//測定結果をミリ秒で返す
long long result() const;
private:
std::chrono::system_clock::time_point _startTime, _endTime;
bool _isStarted;
};
}
#endif
#include "time_measurer.h"
namespace Timer
{
//測定開始メソッド
void TimeMeasurer::timerStart()
{
_startTime = std::chrono::system_clock::now();
_isStarted = true;
}
//測定終了メソッド
void TimeMeasurer::timerEnd()
{
if (!_isStarted) throw "Exception!!!";
_endTime = std::chrono::system_clock::now();
_isStarted = false;
}
//測定結果をミリ秒で返す
long long TimeMeasurer::result() const
{
const auto resultTime = std::chrono::duration_cast<std::chrono::milliseconds >(_endTime - _startTime);
return resultTime.count();
}
}
使用コード
std::string型を引数とした関数を使用して、実行速度を測定しました。各処理を1000000回実行して、その実行時間で比較しました。
//値渡し
void Test(std::string testStr)
{
//ローカル変数に代入する
std::string str = testStr;
}
//ポインタ渡し
void Test2(std::string *testStr)
{
std::string str = *testStr;
}
//参照渡し
void Test3(std::string& testStr)
{
std::string str = testStr;
}
int main()
{
std::string str = "test";
//実行回数
const int count = 1000000;
Timer::TimeMeasurer timer;
timer.timerStart();
//処理を書く
for (auto i = 0; i < count; i++)
{
//値渡し、ポインタ渡し、参照渡しの3種類で測定する
Test(str);
}
//処理終了
timer.timerEnd();
std::cout << timer.result() << "ms"<<std::endl;
}
結果
値渡しが一番実行時間がかかり、ポインタ渡しと参照渡しの2倍以上という結果になりました。Effective C++ 第3版にも書いてありましたが、値渡しは引数渡しの際に、コピーコンストラクタが呼ばれ、新しいオブジェクトが生成されるため、その生成時間分、ポインタ渡しや参照渡しより時間がかかると思います。
種類 | 実行時間 |
---|---|
値渡し | 9569ms |
ポインタ渡し | 4043ms |
参照渡し | 4087ms |
追加として、const参照渡しだとどうなるか気になったので、測定してみました。結果としては、ほとんど差はなかったです。違いとしては、呼び出し先で書き換えが可能か不可能という違いだけだと思うので、実行時間も変わらなかったと考えています。今回はstd::stringを使用しましたが、組み込み型などでも同じ結果になるのか今後試してみようと思います。
種類 | 実行時間 |
---|---|
参照渡し | 4087ms |
const参照渡し | 4094ms |
//const参照渡し
void Test4(const std::string& testStr)
{
std::string str = testStr;
}