|
|
[C++]std::stringの華麗な罠 |
2014年11月28日23:05:57 |
|
文字列を関数の引数に渡す場合こんなコードを思い浮かべるのではないでしょうか? |
1
2
3
4
| void Print( const char* str )
{
printf( "%s\n", str );
} |
書いた後、こう思うはずです。あれ、NULL渡されたらヤバくない?
その通りです。 NULLが渡されたら落ちます。
NULLを許容したい訳じゃないので、NULLチェックを入れるのは面倒だ。
std::stringを利用して参照にしたら完璧じゃない?と閃くはずです。 |
1
2
3
4
| void Print( const std::string& str )
{
printf( "%s\n", str.c_str() );
} |
しかしながら、こいつは完璧じゃありません。
std::stringは文字列のポインタを受け付けている為にNULLを受け取れるのです(涙)
下記のコードはコンパイルが通り実行時に落ちます。
※落ちるタイミングはstd::stringのコンストラクタです。 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include <cstdio>
#include <string>
void Print( const std::string& str )
{
printf( "%s\n", str.c_str() );
}
int main()
{
Print( NULL );
return 0;
} |
実現したかったのはコンパイル時のエラーチェックだったはずなのに
引数がconst char*だった時と何も変わっていません。
結局、文字列を安全に渡すことは出来ないのです…
オブジェクトの参照はコンストラクタの実装により危険性があるので過信せずご利用は計画的に… |
|
[C/C++]マクロの便利な使い方~文字列化・トークン連結演算子~ |
2014年11月27日05:27:22 |
|
知る機会を得るのが難しい機能なのでご紹介します。
マクロ(#define)には便利な演算子が2つあります。
・文字列化演算子 (引数の文字列化)
・トークン連結演算子 (引数をそのままマクロの中に埋め込む)
乱用すると黒魔術化するので用法・用量を正しく守ってご利用下さい。
くれぐれも暗黒面に堕ちないよう祈っています。
まずは文字列化演算子です。
※こちら筆者は具体的なメリットを知りません。不必要に使わなくていいと思います。 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include <cstdio>
#define STRING( s ) #s
int main()
{
printf( STRING( hoge\n ) );
return 0;
} |
出力
hoge |
続いてトークン連結演算子です。
上手く活用すれば、テンプレートに出来ないようなジェネレータに近いものを作り出せます。
テンプレートに出来ないことは次の2つ
・クラス・構造体名の変更
・メンバ変数・メンバメソッドの増減、名称変更 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#define VECTOR_GENERATOR( d, ... ) \
struct Vector##d \
{ \
float __VA_ARGS__;\
}
VECTOR_GENERATOR( 2, x, y );
VECTOR_GENERATOR( 3, x, y, z );
VECTOR_GENERATOR( 4, x, y, z, w );
int main()
{
Vector2 v2;
Vector3 v3;
Vector4 v4;
return 0;
} |
|
[C/C++]文字列リテラルの連結 |
2014年11月25日22:24:10 |
|
あまり語られているサイトを見たことがないのでご紹介です。
文字列リテラルの連結は簡単に出来て便利です。 |
1
2
3
4
5
6
7
8
9
| #include <cstdio>
int main()
{
printf( "aaa" "bbb\n" );
return 0;
} |
出力
aaabbb |
具体的にどういった場面で便利なのかご紹介します。
パターン1
文字列リテラルが長い場合や一定文字数で意味がある時に分割すると見やすくなります。 |
1
2
3
4
5
6
7
8
9
| char reversi[] =
"........"
"........"
"........"
"...OX..."
"...XO..."
"........"
"........"
"........"; |
パターン2
マクロとの組み合わせ
何かしら固定値がつくマクロを用意しておくと繋げて出力するのが容易になります。 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| #include <exception>
#include <cstdio>
int main()
{
try
{
throw std::exception( "○○ exception :" __FUNCTION__ );
}
catch( std::exception& e )
{
printf( "%s\n", e.what() );
}
return 0;
} |
|
|