C++

『Google C++ Style Guide』だってさ

C++

はてなブックマークの「最近の人気エントリー」に『Google C++スタイルガイド日本語訳』というのがあったので、『Google C++ Style Guide』の存在を知ることができた。 日頃は「Google の開発者っていいよなー」と羨ましがることしきりだが、今日は初めて「G…

ポインタ変数なのか、ポインタ型なのか、

C でポインタを定義するときの書き方には、3つの流派があるようだ: ポインタ「変数」派 int *p; 変数 p はポインタ変数という特別な変数だ、という主張。 (p を逆参照*1した結果である) *p の型は int だよ、という形での型付け。 ポインタ「型」派 int* p; …

#include ガードにファイル名を入れるのは止めませんか?

#include ガードといえば、大体こんな感じのがメジャーかと思う: sample.h の #include ガード #ifndef SAMPLE_H #define SAMPLE_H // 宣言・定義など #endif // ifndef SAMPLE_H 実を言えば、こういう #include ガードがあんまり好きじゃない。 もちろん、#…

goto では、デストラクタは呼ばれる

僕は、goto が嫌いだ。まあ、好きな人なんていないとは思うが。一度でも“今は亡き前任者の goto”に泣かされたことがあれば、全ての goto 文は「goto HELL;」にしか見えなくなるはずだ。“goto 文の全てが悪いわけではない”、“多重ループからの脱出には goto …

C++ で longjmp() 関数を使ってはならない

longjmp() 関数を使うと C でも例外処理っぽいことができるわけだが、これは、間違っても C++ プログラム中では使ってはならない。まあ、C++ には本物の例外処理があるので使うわけもないのだが、C との混合プログラミング*1の際などには注意を要する。 問題…

std::auto_ptr_ref と Colvin-Gibbons トリック

std::auto_ptr は、C++ での RAII を実現するにあたって欠かせない重要なクラス((厳密に言えば std::auto_ptr は「構造体テンプレート」だが、面倒なので「クラス」と呼ぶ。))だ。だが、その根底にある move semantics という考え方を正しく理解していないと…

RAII なオブジェクトの生成は独立したステートメントで

C++ では関数呼び出しの際に引数をどういう順序で評価するかは不定なわけだが、まだ認識が甘かった。単に順序が不定なだけではなく、第1引数を途中まで評価して、それから第2引数を評価して、その後で第1引数の残りの評価を……、みたいなことも許されるらしい…

演算子の中置記法と引数の評価順序

C++ では引数の評価順序が不定なわけだが、ここまでは、まあ、知っていた。だが、これには思い至らなかった: 中置記法 std::cout << "result of f(): " << f() << std::endl << "result of g(): " << g() << std::endl; 前置記法 operator << ( operator << …

C++ では、引数の評価順序は不定

あろうことか、C++ では、関数呼び出しの際の引数を評価する順序が不定である*1。“f(g(), h()) で g よりも h が先に呼び出されるかもしれない”なんて思いもしなかった、ではダメなのだ((g や h の呼び出しが f の呼び出しの前に完了していることは保証して…

詳解、new 演算子

new 演算子に対して以下のような疑問はないだろうか? new 演算子と operator new の違いがよく分からない。 プレイスメント (配置構文) new がよく分からない。 クラスのメンバに operator new を用意するというのがどういうことなのかよく分からない。 デバ…

引数にも const や final を付ける

ローカル変数には const や final を付けるわけだが、関数 (メソッド) の仮引数というのは一種のローカル変数なわけで、やっぱり、const やら final やらを付けるべきだ。 C++ でも Java でもこれらの型修飾子はシグニチャには影響しないので、API 仕様が汚…

ローカル変数には const や final を付ける

変更しないローカル変数には、const とか final を付けるべきだ。そして、ローカル変数を変更しないようなプログラミングスタイルにしてもらえると、レビューが楽で助かる。 もちろん、ループカウンタなんかは const にはできない。絶対にできないわけではな…

仮想デストラクタの明示的な呼び出し

オブジェクトの解体の例で、こう書いたことに注意して欲しい: ◎デストラクタの仮想呼び出し object_->~T(); ×デストラクタの非仮想呼び出し object_->T::~T(); T* が指している先が T 型のオブジェクトである保証は当然無い((この例を出したところの記述では…

割当と構築、解体と解放

C++ では、割当*1 (allocation) と構築 (construction)、解体 (destruction) と解放 (deallocation) はそれぞれ全く異なる概念だ。コードで見ると、分かりやすい: /* 割当 */ void* const rawMemory_( ::operator new(sizeof(T)) ); /* 構築 */ T* const obj…

swap には無送出保証の例外安全性が必要

『代入演算子の定石』では、swap には無送出保証の例外安全性が必要だと書いた。これに対して、「これなら原子性保証だけで十分なのでは?」という疑問が湧くかもしれない。ちなみに、こういうコード: some_class& operator = (const some_class& another) { …

代入演算子の定石

代入演算子を実装しなければならない場合は、以下のようにする。 class some_class { public: some_class& operator = (const some_class& another) { some_class tmp_(another); swap(tmp_); return *this; } void swap(some_class& another) throw (); }; …

代入演算子を書かなければならないとき

C++ の場合、特別な理由がない限り、クラスはコピー可能にする。この辺りは、java.lang.Cloneable の位置付けとは全然違うので、Java 慣れしてる人は注意が必要。 代入演算子を宣言しなかった場合、コンパイラが自動的に生成してくれる。これは、以下のよう…