C++プログラマ キャスブログ
[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> // printfに必要なヘッダー #include <string> // std::stringに必要なヘッダー void Print( const std::string& str ) { printf( "%s\n", str.c_str() ); } int main() { // C++11の場合はNULLでなくnullptrを使いましょう。 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> // printfに必要なヘッダー // マクロ定義 // 文字列化演算子は [#仮引数名]が構文です。 #define STRING( s ) #s int main() { // 文字列化演算子を使うと引数の値がダブルクォーテーションで // 囲まれたのと同じ結果になります。 // エスケープ文字(\n)が""で囲まれていないのが非常に気持ち悪いです。 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__;\ // __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> // printfに必要なヘッダー 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> // std::exceptionに必要なヘッダー #include <cstdio> // printfに必要なヘッダー int main() { try { // 関数名をくっつけて例外を投げる。 // __FUNCTION__はVCの書き方です。 // C99の場合は__func__です。 throw std::exception( "○○ exception :" __FUNCTION__ ); } catch( std::exception& e ) { printf( "%s\n", e.what() ); } return 0; }
カテゴリ

リンク
C++11のコードを
試すのに便利です。
http://ideone.com/

同人ゲームを
製作している知人
sorcery

にほんブログ村 IT技術ブログ C/C++へ
にほんブログ村


C++ ブログランキングへ

ゲームダウンロード DefenceTri