プログラミング

プロプロセッサのマクロ展開と ## 演算子 (2)

前回を書いてからすっかり経ってしまったが、C/C++ プリプロセッサのマクロ展開と ## 演算子の話。 まずは、__TEXT がどう解釈されるのかを見てみる: #define __TEXT(quote) L ## quote C++ 標準*1 にはこうある: 『16.3 Macro replacement』の「9」 A prepr…

プロプロセッサのマクロ展開と ## 演算子 (1)

Windows API には TCHAR 型というものがある((MSDN ライブラリでは TCHAR は unsigned char の typedef だと解説されているが、Visual C++ 2008 Express Edition に付いてきた WinNT.h では char の typedef になっていた。)): #ifdef UNICODE typedef wchar…

cd してから実行する

いろいろとあって、svnserve を cd してから実行する、という必要に迫られた。tar の -C オプションみたいなことがしたい((逆に、tar にわざわざ -C があるということは、うまい逃げ道はないのかも。))。 で、sh -c やら exec やら sudo やらをいろいろ弄っ…

バッチファイルで、カレントディレクトリのパスが空白を含まないかを判定する

ちょっといじってみたいところがあって、Subversion を自分のところでビルドしている。 ところが、これがかなり鬱陶しい。Subversion 開発者の皆さんは UNIX ユーザが多いのだろうか? Windows 上でのビルドが一筋縄ではいかない。調子に乗って最新バージョン…

Subversion の属性値もコピーしてくるシェルスクリプト

Subversion でベンダブランチを作る際、一次開発元も Subversion を使っている場合には、属性値も全部そのまま持ってきたい。なんか、そういうツールは絶対どこかにあるんじゃないかとは思うんだが、探せなくて作ってしまった: 適当なワーキングコピー中にあ…

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

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の際などには注意を要する。 問題…

longjmp() 関数と例外処理

C 言語の野放図なパワーを見せつけてくれるのが longjmp() 関数だ。とりあえず、サンプルコードを見てみよう: #include <setjmp.h> #include <stdio.h> void f(jmp_buf jmpBuf) { puts("f() called."); longjmp(jmpBuf, 1); } int main() { jmp_buf jmpBuf; setjmp(jmpBuf); put</stdio.h></setjmp.h>…

コンテキストクラスローダって何だ?

システムクラスローダと似たようなものに、「(スレッドの) コンテキストクラスローダ (context class loader)」というものがある。前々から名前だけは知っていたのだが、特に必要とする機会もなかったので何なのかは知らないままだった。今回、システムクラ…

用語は正しく覚えよう: システムクラスローダとブートストラップクラスローダ

ディスカッションの最中、どうも話がかみ合わないと思ったら用語の使い方が間違っていた、ということが時々ある。同じ概念を違う用語で呼んでいる場合はすぐに気づくので問題ない*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 じゃなくて variable があればいいのに

const をやれ「ローカル変数に付けろ」「引数にも付けろ」と主張していると、「うぜー」と思われる((const がうざいのであって僕がうざいのではない、と信じたい。))。そういうとき、いつも思う: あぁ、デフォルトが const で、どうしても変更可能にしたい変…

引数にも 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 慣れしてる人は注意が必要。 代入演算子を宣言しなかった場合、コンパイラが自動的に生成してくれる。これは、以下のよう…

3種類の例外安全性

関数の例外安全性には、以下の3種類がある。 資源解放保証((「資源解放保証」「原子性保証」「無送出保証」っていう言葉は bold;">いま勝手に作りました、すいません。Exceptional C++ などでは「弱い保証」「強い保証」「投げない保証」と呼ばれていますが…

引数チェックと assert

後輩のコードレビューをしていて、引数チェックはどういう風にするのがいいのか、みたいな話になった。 「どういう風に」といってもいろいろあるが、今日の話題は、以下の2派閥のどっちがいいのかということ: 引数チェックは常にするよ派 void methodA(final…