【C++】配列とVectorとArrayで比較
きっかけ
以前、C++で実装した際に、コードを読まれた方からなんでVectorにしないの?と聞かれたことがありました。
機能面での違いはたしかにありますが、固定サイズならば別に配列でもOKではと思っていたのですが、ふと気になったので調べてみました。
比較対象
比較した方法は次の4通りです。
Vector同士で比較しているのは、配列っぽく使うパターンと、push_backで代入させた場合のものの2種類です。
push_backは遅いと書いていらっしゃる方もいたので、比較として入れてみようと思い、含めました。
コード
ダメダメながらも書いたコードは次に続きます。
やったことはすごく単純で、10万のデータを作って、そのデータから総和を求めるという操作です。
もっと良いベンチマークがあるかもしれませんが…。
配列(一番最初に習うであろうもの)
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; long int a[MAX+1]; // Array start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { a[i] = i; } long int sum1 = 0; for (long int i = 0; i <= MAX; i++) { sum1 += a[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
↑の修正版
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; long int a[MAX+1] ={}; // Array start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { a[i] = i; } long int sum1 = 0; for (long int i = 0; i <= MAX; i++) { sum1 += a[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
Vector(配列っぽく)
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; std::vector<long int> b1(MAX); // vector(like Array) start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { b1[i] = i; } long int sum2 = 0; for (long int i = 0; i <= MAX; i++) { sum2 += b1[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
Vector(push_back)
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; std::vector<long int> b2; // vector(push_back) start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { b2.push_back(i); } long int sum3 = 0; for (long int i = 0; i <= MAX; i++) { sum3 += b2[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
Array(C++11から追加されたもの)
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; std::array<long int, MAX> c; // C++11's Array start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { c[i] = i; } long int sum4 = 0; for (long int i = 0; i <= MAX; i++) { sum4 += c[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
↑の修正版
#include <iostream> #include <cstdio> #include <vector> #include <array> #include <chrono> int main(int argc, char const *argv[]) { std::chrono::system_clock::time_point start, end; double elapsed; const long int MAX = 100000; std::array<long int, MAX> c = {}; // C++11's Array start = std::chrono::system_clock::now(); for (long int i = 0; i <= MAX; i++) { c[i] = i; } long int sum4 = 0; for (long int i = 0; i <= MAX; i++) { sum4 += c[i]; } end = std::chrono::system_clock::now(); elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count(); std::cout << elapsed << "μs" << std::endl; return 0; }
結果
単位はすべて、μsことマイクロ秒(100万分の1秒)。
rev2とついてるものは修正版です。
Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./array.out 792μs Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./array_rev2.out 489μs Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./vector_like_array.out 603μs Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./vector_push_back.out 2962μs Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./array_cpp11.out 827μs Ruby@Kotori-no-MacBook-Pro ~/Desktop $ ./array_cpp11_rev2.out 528μs
やっぱりpush_backは遅いですね。
Vectorを配列っぽく使うと配列と変わらない速度みたいです。
あと意外にもC++11から追加されたArrayはわずかながら配列より遅いみたいです。なぜでしょうか。
と思っていましたが、初期化を行ったうえで再実験行ってみたら配列が一番高速でした。次に、Array(C++11以降)が速いという結果となりました。
まとめ
今後はVectorを配列っぽく使います。
いや、修正した結果、配列が速かったのでやっぱり配列が一番ですね。
追記1(2016.07.09 0:27 UTC+9)
一部のコードを修正前のものを記載していました。修正しました。
なお、結果は修正後のものを記載しているため、変化ありません。
追記2(2016.07.09 0:52 UTC+9)
研究室の先輩(id:togatogah)から、「配列とArray(C++11以降)の初期化されていない可能性があるのに対し、Vectorは構築時に必ず初期化を行うので、配列とArrayを初期化してみてはどうか」という提案がありました。
そこで試してみたところ、大きく結果が変わりました。
id:togatogahさんありがとうございました。
ファニーナイツ ご注文はうさぎですか?? シャロ 1/7スケール PVC製 塗装済み 完成品 フィギュア
- 出版社/メーカー: 青島文化教材社
- 発売日: 2016/05/19
- メディア: おもちゃ&ホビー
- この商品を含むブログ (4件) を見る
猫でもわかるC++プログラミング 第2版 (猫でもわかるプログラミング)
- 作者: 粂井康孝
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/07/27
- メディア: 単行本
- この商品を含むブログ (2件) を見る
- 作者: ビャーネ・ストラウストラップ,Bjarne Stroustrup,柴田望洋
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2015/02/28
- メディア: 大型本
- この商品を含むブログ (11件) を見る
手帳型スマホケース?iPhone6/6S専用?ご注文はうさぎですか???05 シャロ
- 出版社/メーカー: A3
- 発売日: 2016/07/09
- メディア: おもちゃ&ホビー
- この商品を含むブログを見る