Effective C++


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

脱もぐりしたい。第3版。

1週目、どんなことが書いてあるのかを書き流す。


ほか

left hands side

right hands side.

1項C++を複数の言語の連合とみなす

 C++で効率よくプログラミングするには、C++のどのぶぶんを使うかで変わる。

2項defineよりもconst,enum,inlineを。

const で定義するとコンパイラ側から変数名を参照できるメリット

(脱線:こういう視点からすれば、pythonでは変数に格納するより、dictに格納した方がいいのか?)

enumハックについて。

3項可能ならconstを使う。

constがアスタリスクの左にあるとき

const char* hoge = "hogehoge";

は「ポインタが指し示すデータがコンスト」である。

const char* hoge は再代入可能。

char buff[10];
char* const hoge = buff;

hoge自体には再代入不能。

ただし、char*なのでhoge[0]やhoge[1]には代入可能。

ここもう一度。

constなメンバ関数

4項 オブジェクトは使う前に初期化

  • オブジェクトは自動で初期化されるとは限らない、プログラマが初期化コードを書く
  • コンストクタでは代入を行うより、初期化子リストを使う。(コンストラクタの後ろに:でくっつけるアレ)初期化子の順番はデータメンバの宣言順に記述する。

翻訳単位にある「ローカルでない静的オブジェクト」の初期化の順番は決められていない。

「ローカルでない静的オブジェクト」を「関数に対するstaticなオブジェクト」に置き換えることでこの問題を避ける。

=>P19

5項 C++が自動で書き、自動で呼び出す関数を知る

デフォルトコピーコンストラクタとはどんな仕組みになってるのか?

のコードを書かないと怪しい。

デフォルトコピーコンストラクタの動作

6項 コンパイラが自動生成することを望まない関数は使用禁止

コピーコンストラクタの不意の使用を防ぐ。

=>対応するメソッドをprivateなどのテクニックはデザインパターン上でよく見るよね。

7項 ポリモーフィズムのための基底クラスには仮想デストラクタを宣言する

ロベール本でも書いてあったっすな

8項 デストラクタから例外をなげない

万一、デストラクタで例外が発生するようなプログラムを組まなければいけない設計になったときは、

デストラクタがプログラムを中止させるか、その例外をcatchし、対処するコードを書く。

9項 コンストラクタやデストラクタ内で仮想関数を呼び出すことがないようにする。

JavaやC#とはちがうらしい。

この項目をもう一度噛み砕いておきたいところ。

10項 代入演算子は*thisへの参照を戻すようにする

return *this;

これは代入を連続してつなげられるという機能を継続させるため。

a=b=c;


11項 operator=の実装では、自己代入に備える

w=w;

などは意味のないこと+コピーによる膨大な無駄なので、それを備える。

(think.)これは

currentSequence = currentSequence->update();

でやり取りされるポインタの代入とは違う。


12項 コピーするときはオブジェクトの全体をコピーする

コピーコンストラクタ、コピー代入演算子をあわせてコピー関数と呼ぶ。


13項 リソース管理にオブジェクトを使う

think:C++の良いところ(と悪いところ)にリソース管理を自分でできるという点が。


14項 リソース管理クラスのコピーの振る舞いはよく考えて決める

15項 リソース管理クラスには、リソースそのものへのアクセス方法をつける

16項 対応するnewとdeleteは同じ形のものを使おう

17項 newで生成したオブジェクトをスマートポインタに渡すところは、独立したステートメントで行う

13項を見よ:processWidgetはスマートポインタを得られるようにしている。

脱線、explict宣言:

http://marigold.sakura.ne.jp/devel/cpp/explicit.html

引数を1個とるコンストラクタの暗黙呼び出しを禁止するには,
コンストラクタを“explicit”と宣言しておく.
explicit宣言したコンストラクタは,明示的呼び出し(C obj(10);)でしか呼び出せなくなり,
暗黙呼び出しを記述するとコンパイル時エラーになる.

ここの記述をもう一度確認。

ようは、

スマートポインタに渡すのは次のようなコードを書くべき

std::tr1::shared_ptr<Widget> pw(new Widget); //独立したステートメントで書く
processWidget(pw,priority() );

例外が投げられた時、リソース漏れが起こる可能性がある。


18項 インタフェースは正しく使う時には使いやすく、間違った使い方では使いにくくする。

この項をもう一度読み直しておきたい。

  • 良いインタフェースは正しく使う時は常に使いやすく、間違った使い方では使いにくくする。
  • インタフェースに一貫性をもたせる
  • インタフェースの誤用を防ぐには新しい型を定義し、型に作用する演算子の機能やオブジェクト

19項 クラスのデザインを型のデザインとして考える

ここからはC++に限らず、オブジェクト指向のデザインについて言及。

オブジェクト指向をするなら読んでいないときつい。


think:なんかHaskellっぽいな。

  • オブジェクトはどのように生成され、破棄されるのか
  • オブジェクトの初期化と代入は、異なる操作になるか?
  • オブジェクトの値渡しは、具体的にどのようなものになるか? <=コピーコンストラクタ
  • オブジェクトが持てる有効な値はどのようなものになるか?
  • 継承の階層の中にうまくあてはまるか?
  • 型変換はどのような型変換をうけるのか?

これを記述できるとは。

operator double;


20項 関数ではconst参照渡しを利用。

HAL研のプロコンコード参照。

ロベCにも。

21項 参照渡しでリターンしない

なる前本のとおり。コピーコンストラクタがよばれてすっごくおもくなるよ!

22項 データメンバはprivate.

あたりまえっちゃ当たり前だが、pythonではあんまし守ってない自分...。

23項 メンバ関数より、メンバやflendでもない関数をつかう

メンバ関数を付加することにより、privateフィールドにアクセスできる関数が増加、

カプセル化を妨げる原因になるということらしい。

この視点は無かった。素人すぎる・・・。

24項 すべての引数に型変換が必要ならメンバでない関数を宣言すべし。

一種のアダプタパターンのような。

explict属性でたよ。C++で使ったこと無いよ。

25項 例外を投げないswapを考える

std::spawよりももっと効率の良いswapを考えて実装する項。

自分で書き換える必要がある理由も書いてあるが、ちょっと分量が多いので飛ばし。



実装

26項 変数の定義は可能な限り先延ばしせよ

オブジェクト指向ではインタフェース(関数)の方に意味があるが、

それを裏付けることが書いてあるのか?

27項 キャストはコンパイル時の型チェックシステムを駄目にする場合がある、キャストは最小に抑える。

const_cast(s)

dynamic_cast(s)

reinterpret_cast(s)

static_cast(s)

の使い分けは?

28項 オブジェクト内部のデータへのハンドルを戻さないように。

オブジェクト内部で管理しているはずのハンドルをconst get系で返すと、

ハンドルを利用してデータが書き換えられる恐れがある。

それを外部へもらすのは設計として可笑しい。

29項 コードを例外安全なものにする

上手く理解できなかった。もう一度読む。

30項 インライン関数を詳しく知る

ここを飛ばし。

31項 ファイル間のコンパイル依存性を小さく

まだ中身読んでないけど、

オブジェクト(ここではコンパイルによってできる.oやら.objの話)が変更されていない場合は

コンパイル済みのオブジェクトファイルをそのままリンクできるので、

小さいオブジェクトがたくさんあったほうがビルド効率が上がる。

・・・という話ではない様子。再読必要。


継承とオブジェクト指向設計

c++のpublic継承、private継承の部分の記憶がぶっこぬけてる自分。

ロベール本もっかい復習しようか。

32項 public継承はis-a関係を表すようにする

subはsuperのカテゴリなんですね。

33項 継承した名前を隠蔽しないようにする

34項 インタフェースの継承と実装の継承の区別をする

public継承は

「関数インタフェースの継承」「実装の継承」

の2つを一気に行う…ってjavaでもやらん限り気づかんがな。

後でここも読む。

35項 仮想関数の代わりになるものを考える

36項 非仮想関数を派生クラスで再定義しない

ここもう一度読む必要がある。

37項 継承された関数のデフォルト引数値を再定義しない

38項 コンポジションを使ってhas-a関係、is-implemented-in-terms-of関係を作る

コンポジションはオブジェクトが別のオブジェクトを内部に持つような構造のこと。

think:それって集約と何が違う?(追記:集約をコンポジションって言うみたいね。)

39項 賢く使うprivate。

何がどう賢いのかは本文をみないとワカランチン。

40項 多重継承は賢く使う。

インタフェースの多重継承ならまだしも、実装の多重継承は怖い。

まだ本文読んでないので、なんともいえないが。


テンプレートとジェネリックプログラミング

41項 暗黙のインタフェースとコンパイル時ポリモフィズム

42項 typenameの2つの意味を理解する

43項 テンプレート化された基底クラス内の名前へのアクセス方法を知っておく

44項 パラメータに依存しないコードはテンプレートの外へ。

積分計算でインテグラルから定数を分離するような感覚か。

45項 「すべての互換型」を受け取るためにメンバ関数テンプレートを使う

…まったく想像つかんです・・・。読みます中身。

46項 型変換をさせたいなら、メンバでない関数をクラステンプレートの中で定義する

47項 型の情報に関してはtraitsクラスを使う

48項 テンプレートメタプログラミングを意識する


newとdeleteのカスタマイズ。

でた。ゲームコーディングコンプリートでもそうやんないとコンソールゲームでは通用しないって書いてあったけど、

僕はコンソールゲームに携わることはなくなってしまったのでちょっと安心。

49項 new-handlerを理解する

50項 どういうときにnewやdeleteの定義を自分で書くと良いのか理解する。

51項 newとdeleteの定義を自分で書く場合はコンベンションに従う

52項 プレースメントnewの定義を書いたらプレースメントdeleteの定義も書く


いろいろなコト

53項 コンパイラの警告に注意を払う

54項 TR1を含む標準ライブラリになじむ

pythonの標準ライブラリにすらなじめずにいる自分が、c++のライブラリになじめるのか否か。

tr1はスマートポインタですよ、奥さん。

55項 Boostに親しむ。

Boost::Pythonしか使ってないっす。もっとつかうっす。

でもlambdaはイヤッス。

以上。


でも今手元にあるEffectiveC++は借り物で、

なぜか本棚にあるMoreEffectiveC++は自分の所持品という謎。

へビィだぜぇ・・・。