C++に入門（STLは楽しい篇）

さいきんRustとD言語をはじめたのですが、C言語しか知らない僕にとっては、これってC++を知らないと辛いんじゃね？と思いあたるフシが多くなってきまして。以前から、C++は、一度腰を据えて勉強したいと思っていたので、いい機会なのでC++に入門することにしました！！

C言語（C89/90）はある程度知っているので、C++の主要な差分だけ拾っていくことにします（ちなみに僕が現時点でC++について知ってるのは、名前マングルと参照型）。

Cとの差分というと、オブジェクト指向、STL、テンプレート…でしょうか。STLが面白そうだったので、最初はSTLについて一通り眺めてみたいと思います。

##std::vector\<T\>

いわゆる、ベクターというやつですね。ランダムアクセス可能な動的配列。

```C++:
#include <vector>

// 要素数10のベクタ変数を定義
std::vector<int> v(10);

// ベクタの要素数を取得
v.size();  // 10　

// ベクタの要素へのアクセス
v[0] = 100; // v = [100]

// ベクタの末尾に要素を追加
for(int i = 0; i < 4; i++)
    v.push_back(i);  // v = [0,1,2,3] 

// ベクタが空ならばtrue、それ以外はfalseを返す
v.empty();

// ベクタの最終要素を削除
v.pop_back();  // v = [1,2,3] => v = [1,2]

// 2要素目の直後に10個の要素'x'を挿入
v.insert(v.begin()+2,10,'x');

// 3番目から10個分の要素を削除
v.erase(v.begin()+2, v.begin()+12);

// 2番目の要素の直後にv2を挿入
v.insert(v.begin()+2, v2.begin(), v2.end())

```

##std::vector\<T\>::iterator

`end()`は、ベクターの最終要素の一つ後の要素を指すイテレータを返すことに注意。

```C++:
std::vector<int> v(10);

// イテレータを介して、ベクタの各要素に値を代入する。
int i = 0;
for(std::vector<int>::iterator it = v.begin(); it != v.end(); it++, i++)
    *p = i;
// v = [0,1,2,3,4,5,6,7,8,9]

// autoによる型推論を使用(C++11)
int i = 0;
for(auto p = v.begin(); p != v.end(); p++, i++)
    *p = i;

// 配列の各要素を表示
for(auto it = v.begin(); it != v.end(); it++)
    std::cout << *it << " ";
std::cout << std::endl;

// 配列の反転
std::reverse(v.begin(), v.end());

// 指定の値と一致する要素の削除（例ではスペースの削除）
std::remove_copy(v.begin(), v.end(), v.begin(), ' ');

// 指定の値と一致する要素の置換（例ではスペースをプラスに置換）
std::replace_copy(v.begin(), v.end(), v.begin(), ' ', '+');

// 各要素について、2倍した値で更新する
// v = [0,1,2,3,4,5,6,7,8,9]
std::transform(v.begin(), v.end(), v.begin(), [](int x){return x*2;});
// v = [0,2,4,6,8,10,12,14,16,18]

// 2つのベクタの各要素について、掛け合わせた値をコンテナに格納
// v = [0,2,4,6,8]  v2 = [1,3,5,7,9]
std::transform(v.begin(), v.end(), v2.begin(), v.begin(), [](int x, int y){return x*y});
// v = [0,6,20,42,72]
```

##std::list\<T\>

リストは、ベクターとほぼ同様に扱うことができますが、ベクターがランダムアクセスが可能なのに対して、リストはシーケンシャルにしかアクセスできません。

ベクタにはpush_back()、pop_back()が提供されていますが、リストはそれらに加えて、push_front()、pop_front()が提供されています。

splice()の引数に指定したリストは、スプライス後は空になります。

```C++:
#include <list>
std::list<int> lst;

// リストに要素を追加
for(int i=0; i<4; i++)
    lst.push_back(i);

// リストの内容を表示
for(auto it = lst.begin(); it != lst.end(); it++)
    std::cout << *it << " ";
// => [0,1,2,3]

// リストのマージ
lst.merge(lst2);
// lst=[1,2,3] lst2=[1,2,3] => lst=[1,1,2,2,3,3]

// リストのスプライス
for(auto it = lst.begin(); it != lst.end(); it++){
    if(*it == 2)
        lst.splice(it, lst2);
}
// lst=[1,2,3] lst2=[10,11,12]
// => lst=[1,10,11,12,2,3] lst2=[]

// リストの末尾に要素を追加
for(int i = 0; i < 4; i++)
    lst.push_back(i);  // => lst=[0,1,2,3] 

// リストの先頭に要素を追加
for(int i = 0; i < 4; i++)
    lst.push_front(i);  // => lst=[3,2,1,0] 

// リストの末尾要素を削除
lst.pop_back(); // => [0,1,2,3] = > [0,1,2]

// リストの先頭要素を削除
lst.pop_front(); // => [0,1,2,3] => [1,2,3]

```

##感想
STLって楽しい！！`Hello World`を表示しただけで楽しかった頃を思い出しました。

Cでmalloc()からゴリゴリ書いてた身としては、こういうコードが書けるだけで、ウヒョー！となります。とくに、STLとラムダ式を組み合わせると、こんなパワフルなコードが書けるとは。すごいね、C++。

```C++:
// [0..19]のうち、偶数の要素の数を取得

std::vector<int> v;

for(int i=0; i<20; i++)
        v.push_back(i);

 int cou = std::count_if(v.begin(), v.end(), [](int x)->bool{return x%2==0;});
```