組み込みでもC++/C++11を始めよう

はじめに

この記事は,悪い人にそそのかされてC++を初めてしまった先輩方のために書いています.
C++,C++11,STLの機能の中から,お手軽に使えて便利なものをピックアップして紹介しようと思います.
少しでも興味がある人がC++を始めてもらえれば僕としては嬉しいです.

過去記事に似たようなエントリがあるので,こちらも見てみてください.
e2studioを用いてGCC-C-で開発する

お決まり文句ですが,この記事の内容には誤りがある可能性があります.その際ご指摘をいただければ幸いです.
また,僕は割と適当にC++の勉強をしているので,そのあたりお気をつけください.この記事ではほんの一部の機能紹介にとどめているため,よく研究してから使われることをオススメします.

STL

STLとはStandard Template Libraryの略で,C++で用意されている標準ライブラリのことです.とても便利なライブラリなのでふんだんに使っていきたいですね.
ただし,コードサイズが大きくなるため組み込みで使用する際はよく考えてください.僕のマウスはSTL使いまくっていますが今の所問題なく動いています.

ではいきましょう.

std::pair

例えば座標管理を考えるときに,次のような変数を用意すると思います.

1
2
int current_x = 0;
int current_y = 1;

しかし,迷路座標はxとyはペアで考えるべきです.
というわけで,STLのpairを使って定義しましょう.

1
2
3
std::pair<int, int> current_pos(0, 1);
current_pos.first; //0
current_pos.second; //1

std::array

どんなプログラムでも,配列変数をたくさん使っていると思います.次のコードはよくあるミス.

1
2
int arr[16];
arr[16] = 1; //範囲外アクセス

というわけで,ここでもSTLを使っていきましょう.

1
2
std::array<int, 16> arr;
arr.at(16) = 1; //例外が発生(例外無効化なら何も起こらない)

std::vector

きました,可変長配列です!
サイズの変えられる配列を使えます.

1
2
3
4
std::vector<int> vec = {1, 2, 3};
vec.at(2); //3
vec.push_back(4); //vec = {1, 2, 3, 4}
vec.size(); //4

少し話がずれますが,std::arraystd::vectorなどのすべての要素にアクセスしたい場合,次のような方法があります.

1
2
3
4
5
6
for(int x : vec){
std::cout << x << std::endl; //すべての要素が標準出力に出される
}
for(int& it : vec){
it *= 2; //すべての要素が2倍される
}

std::queue

キューを自前で作っている人や,歩数マップ生成ルーチンとキューが一体型になっている人がいらっしゃるようですが,ここでもSTLを使いましょう.

1
2
3
4
5
6
7
8
std::queue<int> que;
que.push(1);
que.push(2);
que.front(); //1
que.pop();
que.front(); //2
que.pop();
que.empty(); //true

std::bitset

頑張ってビット演算をしていろいろなデータを格納しているかもしれませんが,ここでもSTLを使います.

1
2
3
4
5
6
std::bitset<8> bs; //0b0000
bs.set(); //0b1111
bs.reset(1); //0b1101
bs.test(0); //true
bs.test(1); //false
bs.to_string(); //"1101"

C++

auto

ちょっと使いたいだけのときに一々型を調べるの,面倒じゃないですか? そんなときには楽をしちゃいましょう.

1
2
3
4
5
6
for(auto x : vec){
std::cout << x << std::endl; //すべての要素が標準出力に出される
}
for(auto& it : vec){
it *= 2; //すべての要素が2倍される
}

enum class

使い勝手の良い列挙型です.

1
2
3
4
5
6
7
8
9
10
enum class N : uint8_t{
N1,
N2 = 100,
N3,
N4,
};

N1; // 存在しない
N::N1; // 0
N::N4; // 102

cast

キャストにも幾つか種類がありますが,一番良く使うのはこのキャストです.できるだけ明示するようにしましょう.

1
2
3
4
int a = 10;
float b = static_cast<float>(a) * 2.0f;

uint8_t c = static_cast<uint8_t>(N::N1);

参照渡し

C言語でアドレスを渡す際にはポインタしかありませんでした.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct foo{
int x;
int y;
};
void hoge(int *a, struct foo* b){
*a = b->x;
return;
}
int main(){
int a = 10;
struct foo = {1, 2};
hoge(&a, &foo);
return 0;
}

正直いろいろと面倒くさい,そんなときはC++の参照渡しです.constも付けられます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct foo{
int x;
int y;
};
void hoge(int& a, const struct foo& b){
a = b.x;
return;
}
int main(){
int a = 10;
struct foo = {1, 2};
hoge(a, foo);
return 0;
}

constexpr

配列のサイズを指定するには,定数かマクロを使うしかありませんでした.

1
2
#define SIZE 10
int x[SIZE];

このサイズがコンパイル時に確定する場合(ex.他のパラメータから配列サイズが決まる場合),どうすればいいでしょうか?
C++11ならconstexprを使いましょう.

1
2
3
4
constexpr int size1 = 10;
constexpr int size2 = size1 + 5;
int x[size1];
int y[size2];

おわり

第一弾おわり!
(つづくの!?)