C++速度実験その3!メンバ変数とthisポインタ
はじめに
更新に空きができてしまいましたが,C++速度実験その3です!
ちなみに前回は,C++速度実験その2!vector配列の扱いについて
今回のテーマはズバリthisポインタです.
thisポインタはクラスのメンバ関数内で使用できる,自身のクラスを指すポインタです.
thisポインタ
thisポインタは,通常メンバ関数内からメンバ変数を呼び出すときに使用しますが,もしそのメンバ関数内に参照したいメンバ変数と同じ名前がを持ったローカル変数が無ければ省略が可能です.
これはC言語にはなくC++から導入されたようです.
つまりこいうこと!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <iostream> class sample{ private: std::string str1 = "member1"; std::string str2 = "member2"; public: void function(); }; void sample::function() { // thisポインタでメンバ変数にアクセス std::cout << this->str1 << std::endl; // 省略可 std::cout << str1 << std::endl; // ただし同じ名前のローカル変数がある場合は // 何もつけないとローカル変数優先になる std::string str2 = "local"; std::cout << str2 << std::endl; std::cout << this->str2 << std::endl; } int main(){ sample s; s.function(); return 0; } |
1 2 3 4 | member1 member1 local member2 |
このように,正直thisポインタは特に使わなくても何とかなるのですが,明示的に分かりやすい上に,セッターなどで引数の名前を,実際に代入するメンバ変数と同じに設定できるので,コードの可読性は向上するかと思います.
そんなわけで,僕は基本ローカル変数で同じ名前が無くとも,thisポインタはよく使っています.
実験目的
さて,今回そのthisに関する速度実験をするわけですが,果たして
thisポインタを付けた場合と付けない場合で実行速度に差は出るのか.
という疑問から実験を行っていきます.
また,並行して関連した実験も行いますよ~.
実験条件
まず比較する条件を紹介します.
どの実験でも共通しているのが,以下の
1 2 3 4 | class test{ private: double a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0, a7 = 0, a8 = 0, a9 = 0, a10 = 0; }; |
という test クラスに属する double 型のメンバ変数10個に100,000,000回アクセスします.
それを100試行行い,かかった時間の平均値を比較する形をとります.
実験0 (baseline):thisポインタを使わない
1 2 3 4 5 6 7 8 9 10 | /** * メンバ変数にthisポインタを使わずにアクセス! */ void test::exp1_0() { for( int i = 0; i < 100000000; ++i ){ auto a = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10; } } |
実験1:thisポインタを使う
1 2 3 4 5 6 7 8 9 10 | /** * メンバ変数にthisポインタを使ってアクセス! */ void test::exp1_1() { for( int i = 0; i < 100000000; ++i ){ auto a = this->a1 + this->a2 + this->a3 + this->a4 + this->a5 + this->a6 + this->a7 + this->a8 + this->a9 + this->a10; } } |
実験2:予めローカルにthisポインタを確保しておく
1 2 3 4 5 6 7 8 9 10 11 | /** * 予めクラスポインタを関数内で確保する. */ void test::exp1_2() { test* t = this; for( int i = 0; i < 100000000; ++i ){ auto a = t->a1 + t->a2 + t->a3 + t->a4 + t->a5 + t->a6 + t->a7 + t->a8 + t->a9 + t->a10; } } |
実験3:ローカル変数にメンバ変数をthisを使って確保しておく
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 最初にローカルな変数として,メンバ変数を保持. */ void test::exp1_3() { double a1 = this->a1; double a2 = this->a2; double a3 = this->a3; double a4 = this->a4; double a5 = this->a5; double a6 = this->a6; double a7 = this->a7; double a8 = this->a8; double a9 = this->a9; double a10 = this->a10; for( int i = 0; i < 100000000; ++i ){ auto a = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10; } } |
実験4:ハイブリッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * ハイブリッド型. */ void test::exp1_4() { test* t = this; double a1 = t->a1; double a2 = t->a2; double a3 = t->a3; double a4 = t->a4; double a5 = t->a5; double a6 = t->a6; double a7 = t->a7; double a8 = t->a8; double a9 = t->a9; double a10 = t->a10; for( int i = 0; i < 100000000; ++i ){ auto a = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10; } } |
以上5つの条件で比較していきます.
実行環境
IDE | CLion 2018.3.3 © Jetbrains |
CPU | Intel(R) Core(TM) i7-5500U CPU @2.40GHz(4 CPUs) |
メモリ | 8GB |
実験結果
実験0 | 0.45108 s |
実験1 | 0.46661 s |
実験2 | 0.43032 s |
実験3 | 0.32787 s |
実験4 | 0.35778 s |
なんと,実験3が一番速かった.
とにかく分かったことは,
- thisポインタの有無は実行速度に影響がほとんど出ない.
- thisポインタをローカルに確保しても実行速度に影響がほとんど出ない.
(むしろひと手間増えて遅くなる??) - メンバ変数へのアクセスは時間がかかるので,何度も参照する場合はローカルにコピーしておくのが吉.
以上.