『プログラミング言語 C++ 第4版』(ビャーネ・ストラウストラップ著)第4章の学習メモ。
本章で重要と感じた・疑問に思ったポイントの要約と、理解があいまいだった用語の整理を行う。
用語メモ
用語 | ページ数 | 用語の意味 |
---|---|---|
コンテナ | 103 | オブジェクトを内部に保持することを主目的としたクラス。 |
平衡2分木 | 108 | 常に自動で形を調整して、探索性能が落ちない二分探索木。std::mapはこれで実装されている。 |
ハッシング | 108 | データ(キー)を入力すると、ある規則にしたがって「固定長の数値(ハッシュ値)」に変換する手法。 |
ハッシュ | 110 | あるデータを、決まった規則で「数値」や「短いビット列」に変換したもの。 |
シーケンス | 110 | 順番を持った要素の並び。 |
番兵 | 115 | 探索やループの処理を簡単にするために置く「特別な値」。 |
述語 | 116 | 条件判定や真偽を返す関数や関数オブジェクト。 |
重要・疑問ポイントまとめ
(std::cinについて)デフォルトでは、スペースなどの空白類文字は読み取りを終了させる。(p101)
void input() {
for(Entry e; cin>>e;);
phone_book.push_back(e);
}
コピーが望ましくないときは、参照やポインタ、あるいはムーブ演算を使うべきだ。(p104)
補足されなかった例外に驚かされる機会を最小限に抑えるには、mainをtryブロックとして定義するとよい。(p106)
int main() {
try {
// 何らかのコード
} catch(...) {
cerr << "unknown exception throw\n";
}
}
要素数が少ない場合はlistよりもvectorのほうが性能がよい。~特に理由がなければ、vectorを使ったほうがよい。(p107)
(std::mapについて。要素を探索・追加するときは)
[ ]
ではなく、find()やinsert()を使うとよい(p108)
mapの添字演算[]
でkeyが見つからなかった場合、valueのデフォルト値をもつ要素が、自動的にmapに追加される。大抵、それは設計上意図したことではないため、これをなるべく避けるため。
特別に理由がない限り、要素のシーケンスを表す必要があるときは、デフォルトでは標準ライブラリvectorを使うべきだ(p110)
標準コンテナとback_inserter()を使うと、realloc()のような、エラーにつながりやすいC言語方式のメモリ管理をわざわざ使わなくてもよいことになる。(p111)
反復子を使うと、アルゴリズムとコンテナが分離できる。(p113)
アルゴリズムはイテレータだけに依存し、コンテナの種類に依存しない。
だから同じアルゴリズムを複数のコンテナで再利用できる。
アルゴリズムの一般的な定義は、"特定の問題を解くための一連の演算を提供する有限個の規則であり、しかも五つの重要な機能である、有限性、確定性、入力、出力、効率性をもっているもの"である。(p117)
ストラウストラップ先生からのアドバイス
( "→" 以降は補足説明。)
-
車輪の再発明をしないように。ライブラリを利用しよう。
→ 事前に「こういうライブラリがある」と知識を持っているといちばんいいが、標準ライブラリだけでもかなり数があるのでそれも難しい。作りたいものがあるときは、検索するなり生成AIに聞くなりしてすでにライブラリにないか確認するのがよい。 -
選択できるならば、他のライブラリよりも標準ライブラリを優先しよう。
→当たり前だが、標準ライブラリを上回る性能を持つ野良ライブラリは少ない。 -
標準ライブラリが万能であると考えないように。
→例えば、vector
は範囲チェックを保証しない。 - 利用する機能のヘッダファイルの
#include
を忘れないように。 - 標準ライブラリの機能は、
std
名前空間に定義されていることを覚えておこう。 -
C言語スタイルの文字列よりも
string
を優先しよう。
→高機能かつ安全性も高いため。 iostream
は、型を識別するし、型安全であって拡張性にも優れる。T[]
よりも、vector<T>、map<K,T>、unorderd_map<K,T>
を優先しよう。- 標準コンテナの長所と短所を把握しよう。
- デフォルトのコンテナとして、
vector
を利用しよう。 -
コンパクトにまとめられたデータ構造を優先しよう。
→list
は各要素ごとにポインタを持つので非コンパクト。vector
やarray
はコンパクト。 - 確信が持てない場合は、
Vec
のような範囲チェック付きベクタを選択しよう。 -
コンテナへの要素追加には、
push_back()やback_inserter()
を使おう。
→直接添字アクセスで範囲外代入をしないため安全であり、かつリサイズを自動で処理してくれて便利。 -
配列を
realloc()
するのではなく、vector
にpush_back()
しよう。
→手動のメモリ操作はバグの温床になりやすい。 main()
では、あらゆる例外を捕捉しよう。-
標準アルゴリズムを理解して、手作りのループよりも優先しよう。
→手作りループは境界条件やインクリメントの書き間違いが起こりやすい。 -
反復子の利用が面倒であれば、コンテナアルゴリズムとして定義しよう。
→std::sort
ではなくlist.sort()
のような形で定義する、という意味? -
完全なコンテナには、範囲forループが利用できる。
→「完全なコンテナ」というのは、STLやイテレータを正しく提供する自作コンテナのこと。