C++
最近@karino2さんのポッドキャスト「プログラム雑談」のバックナンバーをいろいろ聴いている: anchor.fm 二週間ほど前に書いた聴いてるポッドキャストの記事ではまだ「気になっている」という分類だったのだけど、聴き始めたらいい感じにゆるいのと技術的な…
「C++は基本的に型安全。コンパイルするなら本来unsafeなことはしない」とはじまるこの項目。本当か? 「キャストしなければ・・・」と続くわけだが、それにしたって今まで読んできた中にもどれだけundefined behaviourをうっかり踏みそうな地雷を見てきたと…
古き良きCの作法だと使う変数はすべて関数の一番最初に宣言しておくものだった。 モダンなCだとその必要はないが、C++だとむしろ強く非推奨になる。 いくつかの理由がある。 一つには、変数宣言はその場でコンストラクタの実行を伴い、またスコープから出る…
C++にはpimplというイディオムがある。 何か大きなデータを持つオブジェクトがある場合、単純にデータメンバとしてしまうと(例えば関数にデータを渡したりする時に)コピーが発生するとコストが高い。 そういう場合には、データを実際に保持するクラスと、…
ごくたまに暗黙の型変換が役にたつ時がある。特定の数字を表現するクラスを定義する時などである。 class Rational { private: const int numerator, denominator; public: Rational(int numerator = 0, int denominator = 1); const Rational operator*(con…
前回の項目でカプセル化の重要性について書いてあったが、そのカプセル化を最大に実現するためには、内部実装に触れることのできる面積を最小化する必要がある。 つまり、メンバ関数、フレンド関数といった「クラス内部のデータメンバに直接アクセスできる関…
クラス内のデータはpublicでもprotectedでもなくprivateにしよう。という話。 ポイントは三つ 構文の統一 データアクセスレベルのコントロール カプセル化 構文の統一 オブジェクトのAPIはすべて関数(か演算子)になり、a.somethingだったかa.something()だ…
前回の項目を理解するとなんでもPass-by-Referenceしたくなるが、ReferenceはそもそもちゃんとReferenceを返した先でも存在し続けるオブジェクトのものでなければならず、その条件が満たせないことも多い。という項目。 例えばAクラスにoperator*を定義して…
Pass-by-valueとpass-by-const-referenceのどちらか迷った時は大抵pass-by-const-referenceを選ぼう、という項目。 void printName(MyObj o) { std::cout << o.name(); } void printName(const MyObj& o) { std::cout << o.name(); } 前者がpass-by-value、…
新しいクラスを宣言・定義するのは、C++の型システムの拡張に他ならず、型デザインなので本来簡単なことではない。という項目。 以下のことに気をつけるべき: 新しい型のオブジェクトの生成・破棄方法 初期化と代入の関係 Pass-by-valueの意味 型の性質上取…
リソース管理の部分は少し後回しで、項目をいくつか飛ばして18番目。 いいインタフェースとは、という項目で大きく分けて: 引数をClass/Struct化 インタフェースは統一しよう 戻り値にスマートポインタを使おう 上記三点の話題が挙がっている。 引数をClass…
オブジェクトのコピー関連のメンバ関数は(C++11より前の場合)Copy ConstructorとCopy Assignmentの二つ。(C++11以降はMove関連のものも・・・) これらはコンストラクタとデストラクタと合わせて、コンパイラがデフォルトで書いてくれる、という話は以前の…
例えばBオブジェクトがprivateデータメンバとしてAオブジェクトへのポインタを保持しているとする: class A {}; class B { private: A* pa; public: B& operator=(const B& rhs) { delete pa; pa = new A(*rhs.pa); return *this; } }; 上記のようなoperato…
operator=は*thisを返すようにしよう、という話。 x = y = z = 15という構文が可能なのは、右から評価されていくoperator=が左辺のオブジェクトを返しているから。 ただの慣習だが、よっぽどの理由がない限り従うべき慣習である。 個人的にも異論はない。
C++のコンストラクタは、まず最下層のベースクラスのものが呼び出されて、順次初期化されていって最終的に実際に作成されるオブジェクトのコンストラクタの処理が走る、という流れになる。 class A { public: A(); virtual void init(); }; A::A() { init();…
例外を投げるデストラクタはUndefined Behaviorになると考えるべき。 デストラクタから例外を投げる可能性のあるオブジェクトを要素に持つvectorが破棄されるときに、同時に複数のExceptionが発生してしまう状況があり得る、というのが非常に納得のいく例。 …
なんのこっちゃ。というのはさすがに嘘だが結構頭の中でパースするのが大変な文ではある。 1. Base Classというのは継承を前提としたクラス。 2. Polymorphic Base Classとは、継承した子クラスをベースクラスのインタフェースを通して使用することを前提と…
前回の項目から続いて、コンパイラが勝手に書いてくれるメンバ関数がお節介だったら?という話。 特にcopy assignmentなどはいらない、うっかりどこかでcopy assignするような処理を書いてしまったらちゃんと静的にエラーが検出されてほしい、というような時…
第4項目抜けてた・・・ C++だとオブジェクトが自動的に初期化されないことも多いよ、明示的に初期化しよう、というお話。 初期化されていない変数の値を読もうとするのは未定義な動作を踏むことになる。プラットフォームによってはランタイムエラーなのか?…
ここから第2章。Constructor/Destructor/Assignment関係の話題。 class Empty {}; クラス定義がこれだけでも、Empty型のオブジェクトが初期化されたりコピーされたり代入されたりする記述があれば Constructor Destructor Copy Constructor Copy Assignment…
constできるところは全部constで。というお話。 それなら変数全部デフォルトでconstだったらよかったのでは?と一瞬思ったがrust面に落ちかけているな。(どちらかというとC++がダークサイドか) この章の話題は主に二つ。 ポインタやイテレータのconst化に…
Effective C++の第2項目 Cの遺産である#defineを使いたくなるようなケースのほとんどでは、const、enum、inlineといったC++機能で代用できるし代用するべきだ、という主張。あるいは「プリプロセッサよりコンパイラに仕事をさせよう」。 そもそも私はCをあま…
最近本当に「俺はC++を雰囲気で使っている」と実感しているので、Scot MeyersあたりからはじめてHerb SutterやAndrei Alexandrescuの著作などをいろいろ読んでいきたい。ということで備忘録的にメモ。 まず手始めにEffective C++。数章に分かれて、全部で5…