Copyright 1999 Rogue Wave Software
Copyright 1999 Sun Microsystems, Inc.
よくある誤り |
18 |
![]() |
この章を書く際、技術サポート文書を検討することによって、ユーザーがこれまでに起こしてきた誤りの中で共通しているものを挙げました。さらに予防することのできる誤りについては、それが起こらないよう、ライブラリを書き換えるように努めました。これは常に最良の方法であるといえますが、常に可能であるとは限りません。たとえば、著しくパフォーマンスを低下させることがあります。あるいは、言語の制約から変更できないこともあります。
この章には、最も一般的な誤りのうち、こうした予防措置を行なった後も起こり得るものをまとめてあります。この章に目を通し、問題がある場合は、本書のほかの章もよく読んでください。Rogue Wave ライブラリは、プログラミングエラーの悩みをよく理解した開発者によって作成されたものです。
仮想関数の再定義
既存のクラスからサブクラスを作り、仮想関数を上書きする (無効にする) 場合は、上書きする関数が上書きされる関数とまったく同じ形式を持つようにしてください。これには "const" 修飾子も含まれます。
この問題が起こるのは特に新しい RWCollectable クラスを生成するときです。
例:
class MyObject : public RWCollectable { public: RWBoolean isEqual(); // "const" がない };
MyObject obj; RWCollectable* c = &obj; c->isEqual(); // RWCollectable::isEqual() が呼び出される
作成直後、Tools.h++ の反復子の位置が形式上は不定になっています。したがって、進めるか位置付けるかのどちらかを行わないと、反復子の位置は定義されません。確実な方法は、「進めてから戻る」です。コレクションの最後に達した場合、進んだ後の戻り値は特殊で、反復子の型に応じて false または NULL になります。
したがって、適切なコードは次のようになります。
RWSlistCollectables ct; RWSlistCollectablesIterator it(ct); . . . RWCollectable* c; while (c=it()) { // c を使用する }
Rwvistream& operator>>(RWvistream&, RWCollectable*&); RWFile& operator>>(RWFile&, RWCollectable*&);
main(){ RWCollectableString* string = new RWCollectableString; RWFile file("mydata.dat"); // 誤り: file >> string; // メモリーリーク // 正しい: delete string; file >> string; }
インクルードパス
Tools.h++ ヘッダファイルへのインクルードパスを指定するときに、最後に "rw" を付けないようにしてください。
# 正しい: CC -I/usr/local/include -c myprog.C # 誤り: CC -I/usr/local/include/rw -c myprog.C
そうしないと、リンカーから「未定義の外部参照」などのエラーが出されます。あるいは、プログラムが実行されても、期待どおりに実行されないおそれもあります。
関連するメソッドの整合性を維持する
Tools.h++ で使用されるクラスを設計する場合、「決して使用されないことがわかっている」ために、単純 hash メソッドや operator<() の提供などを省略したくなる場合があります。このような判断を下すと、後で保守を行うときに障害が生じるおそれがあります。正当な理由がないかぎり、operator<()、operator==()、compareTo()、isEqual() などが同じ情報にもとづくようにする必要があります。また、相互に isEqual() か == である値が同じハッシュ値を持つようにする必要もあります。そうしないと、これらの値をハッシュ技法を使用するコレクションに挿入したときに、検出できなくなります。最初の時点で少し手間をかけるだけで、デバッグに要する時間を大幅に削減することができます。
DLL
Tools.h++ の DLL バージョンはラージメモリーモデルを使用するので、そのモデルを使用するデータセグメントすべてを固定する必要があります。たとえば、データセグメントに RWCollectable オブジェクトを作成して、それを Tools.h++ コレクションに挿入した場合、そのコレクションは 4 バイトのポインタを保持することになります。データセグメントを移動した場合、ポインタは無効になります。したがって、.DEF 定義ファイルに次のようなコードを必ず入れてください。
DATA PRELOAD FIXED
ライブラリ機能の活用
最も多く起こりうる誤りはライブラリ機能を最大限に使用しないことです。もし、何かちょっとした補助的クラスを書いていることに気がついたら、ちょっと立ち止まって考えてみてください。なぜそれが必要なのかと。自分の書いているものが少し雑然としていると思える場合にはもっと良い方法がある可能性があります。Tools.h++ のマニュアルの中に求めている情報が見つかるかもしれません。
よくある例を示します。
main(int argc, char* argv[]){ char buffer[120]; //オーバーフローの可能性あり ifstream fstr(argv[1]); RWCString line; while (fstr.readline(buf,sizeof(buf)) { line = buf; //余分なコピー cout << line; } }
main(int argc, char* argv[]){ ifstream fstr(argv[1]); RWCString line; while (line.readLine(fstr)) { cout << line; } }