C++11 に合った書き方 その2
昨日の続きです。C++11 らしい書き方のページについて、気になるものを中心に書いていきます。
C++11 らしい書き方とは
スマートポインタを使え
スマートポインタを積極的に使え、ということのようです。
これまでにも、auto_ptr
がありました
しかし、このauto_ptr
は非推奨となり、代わりにunique_ptr
を使えとのことらしいです。
私は、関数内部でnew
したインスタンスをauto_ptr
にくるんで返り値として返す、ぐらいしかauto_ptr
を使っていませんでしたが、そういった場合は、auto_ptr
のムーブセマンティック考慮版とも言えるunique_ptr
の出番のようです。
その他には、既に多くの処理系で実装されているshared_ptr
などが標準として入るようになりました。
これまでにも使っていましたが、仕事で使う際に、「仕様に入っているから」と堂々と使えるようになるのはありがたいことです。
nullptr
これは、単純に0
でもNULL
でもなく、新予約語のnullptr
を使いましょう、ということです。
C++ では、C言語と異なり、void *
を任意の型のポインタに代入することができません。例えば、以下のようにNULL
を定義していると、C++ ではコンパイルエラーとなります。
1 2 | #define NULL ((void *)0) char *ptr = NULL; // コンパイルエラー (C言語では OK) |
そのため、基本的にNULL
は、単なる 0 と定義されています。
C++ では 0 は特殊な扱いをうけており、何も指さないポインタの値として、任意の型のポインタに代入することができると定められています。
一方で、0 は整数値なので、NULL
を 0 と定義した場合、以下のようなオーバーロードされた関数がある場合に、多くのプログラマの直感と異なる挙動を示してしまいます。
1 2 3 4 5 6 7 8 | void func( int num); // (1) 引数が int の関数 void func( char *ptr); // (2) 引数が char* のオーバーロードされた関数 #define NULL 0 void test() { func(NULL); // NULL は 0 なので、(2) ではなく (1) が呼ばれる。 } |
このように、直感と異なり (1) が呼ばれてしまいます。
C++11 では、このような事態を避けるために、nullptr
という新たな予約語を定義し、何も指さないポインタの値として使え、かつ整数として扱われないものが導入されました。
Uniform Initialization and Initializer Lists
ここに例として挙がっているものと同様な下記コードで、私も以前にとても困ったことを覚えています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class A { }; class B { public : B( const A &a); }; void func() { B b(A()); // (1)「『返り値の型が A である関数ポインタ』を引数にとり、 // 返り値の型が B である関数 b」の宣言 B b((A())); // (2) B 型の変数 b のコンストラクタに A の一時オブジェクトを与えている B b = { A() }; // (3) C++11 で可能になる書き方 } |
最初は (1) のようなコードを書いており、なぜコンパイルエラーになるのかがまったく分からず、ふとしたはずみで (2) のように書くとコンパイルが通ったことを覚えています。
C++11 では、{
, }
による初期化が可能になるので、これらを使うことで、上の例のような場合を避けることができるようです。
また時間があれば、しっかりと C++11 の勉強もしようと思います。
0 件のコメント:
コメントを投稿