|
|
[C++11]auto変数を使おう!ただし慎重に... |
2014年11月22日01:15:32 |
|
auto変数は型推論をして自動的に型を割り振ってくれる非常に便利なものです。 |
1
2
3
| auto i = 10;
auto f = 10.0f;
auto d = 10.0; |
一見便利なのですが、プログラマ自身は型を知っておく必要があるので
元に戻すには脳内コンパイルおよび目グレップを行わなくてはなりません。
読み手が困るだけなので、乱用はオススメしません。
効果的な使い方は型が自明でかつ、その場で利用するものが好ましいでしょう。
私が利用する場合は、イテレータやラムダ式での利用のみです。 |
1
2
3
4
5
6
7
| #include <array>
std::array<int,5> arr = { 1, 2, 3, 4, 5 };
for( auto i=arr.begin(); i != arr.end(); ++i )
{
} |
1
2
3
| auto lambda = [](int i){ return i; };
lambda( 10 ); |
autoの注意点です。
型推論時に付いていれば別ですが、constや参照は自動で付けてくれません。
その辺りは手動で行わなくてはならないので、意識する必要があります。
困る事例はforeachを利用した場合です。 |
1
2
3
4
5
6
7
8
|
#include <array>
std::array<int,5> arr = { 1, 2, 3, 4, 5 };
for( auto i: arr )
{
i = 10;
} |
正しくはこうです。 |
1
2
3
4
5
6
7
| #include <array>
std::array<int,5> arr = { 1, 2, 3, 4, 5 };
for( auto& i: arr )
{
i = 10;
} |
コンテナの中身がオブジェクトの場合には参照をつけておかないと
コピーコンストラクタが毎回走ってしまう悲惨なことになります。
細心の注意を払わなければならない機能なのでもろ手を挙げてオススメはできないですね…
余談ですがauto変数って始めて聞いたとき「記憶クラス」の事だよねーって一瞬本気で思いました。
[記憶クラス]
auto: 自動変数(ローカル変数) ※省略するとこれになる
extern: 外部変数
static: 静的変数
register: レジスタ変数 ※可能な限りレジスタを使う
ちなみにintの変数宣言をフルスペック(?)で書くとこんな感じになります。 |
1
| auto signed int i; |
同じキーワードで紛らわしいと思ったものです。 |
|
[C++11]ラムダ式(無名関数、匿名関数)とstd::function |
2014年11月21日00:10:24 |
|
ラムダ式とは簡単に言えば関数内に作成できる一時的な関数です。
基本的な書き方はこちら |
1
2
|
[](int a, int b) -> int { return a+b; }; |
呼び出し方は普通の関数と同じ呼び方です。 |
1
2
|
int result = [](int a, int b) -> int { return a+b; }( 1, 2 ); |
上記のような使い方は全く意味がありませんね。
処理をそのまま書いておけって感じです。
そこで関数ポインタに入れることによって効力を発揮するのですが
無名関数、匿名関数といいつつも関数ポインタには代入出来ません。
な、なんてこったー!!
ということでstd::functionを利用しましょう。 |
1
2
3
4
5
6
7
8
9
10
| #include <functional>
std::function< int(int,int) > lambda = [](int a, int b) -> int { return a+b; };
int result = lambda(1,2); |
お待たせしました。キャプチャについての説明です。
ラムダ式は外側のスコープの変数にアクセスできます。
その機能のことをキャプチャと呼びます。
書き方は先ほどの[]の中に指定子を書きます。
[=] 外側のスコープの変数はコピーとして扱います。
[&] 外側のスコープの変数は参照として扱います。 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| #include <functional>
int c = 100;
std::function< int(int,int) > lambda = [=](int a, int b) -> int { return a+b+c; };
int result = lambda(1,2);
std::function< void() > write = [&]() -> void { c=200; };
write();
result = lambda(1,2); |
[=]と[&]は外側全ての変数に対して指定するキーワードですが
安全性を確保する為に個別に指定も可能です。
[]内に使用する変数名をそのまま書けばOKです。
何も付けなければ代入となり&を付けると参照になります。 |
1
2
3
4
5
6
7
8
9
10
| #include <functional>
int c = 100;
int d = 200;
std::function< int(int,int) > lambda = [c,&d](int a, int b) -> int { return a+b+c+d; };
int result = lambda(1,2); |
余談ですが、キャプチャに対してconstを付けたいと思ったのは私だけでしょうか
例えばこんな感じにです。
[const &]
ラムダ式の中で書き換えが行われない事が保証できて安全だと思うのです。
現在の仕様では出来ないようですが、将来的な改善に期待したいです。 |
|
[C++11]イテレータとはおさらばforeach |
2014年11月20日07:46:02 |
|
コンテナを回すのに長ったらしいイテレータとはもうおさらばです。
C++11からはforeachを使いましょう! |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #include <vector>
#include <cstdio>
std::vector<int> vec = { 1, 2, 3, 4, 5 };
for( std::vector<int>::iterator i=vec.begin(); i != vec.end(); ++i )
{
printf( "%d\n", *i );
}
for( int i : vec )
{
printf( "%d\n", i );
} |
普通の配列にも使えます。 |
1
2
3
4
5
6
7
8
| #include <cstdio>
int arr[] = { 1, 2, 3, 4, 5 };
for( int i : arr )
{
printf( "%d\n", i );
} |
中身を書き換えるなら参照に |
1
2
3
4
5
6
| int arr[] = { 1, 2, 3, 4, 5 };
for( int& i : arr )
{
i = 0;
} |
コンテナの中身がオブジェクトの場合は参照をつけておかないと
コピーコンストラクタが走るのでご注意を |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #include <string>
#include <cstdio>
std::string arr[] = { "a", "b", "c", "d", "e" };
for( std::string i : arr )
{
printf( "%s\n", i.c_str() );
}
for( std::string& i : arr )
{
printf( "%s\n", i.c_str() );
}
for( const std::string& i : arr )
{
printf( "%s\n", i.c_str() );
} |
|
|