PPPUC++#10
8.1 Technicalities
8.2 Declarations and definitions
あとは退屈なのが続くのでかなりはしょって・・・
- 宣言は「その名前」を「現在のスコープに入れる」操作
- 定義はその名前の内容(実装)を書く操作
- 定義は宣言でもある
- 同じ名前宣言は何度でもできるけど(無意味だが)定義はダメ
- 定義と宣言はなぜわかれているか?
- それはI/Fと 実装を分けられるようにするため。
- externとか滅多に使わねー(とのこと。グローバルいうな方向ですね)
- extern "C"ってのは やっぱ Mr.S的には Bad なんだろう
- 宣言はフットプリントに影響しない。定義はメモリを消費する。
- 分割コンパイルの話
- なぜ前方参照必須なのか(使用前に宣言が必要なのか)
- 技術的な問題。逃げた(とは書いてませんが・・・)
- クラスメンバでは大丈夫なのに・・・
- 本読むときもそうだよねとか、ちょっと苦しいかも。まあ外部関数と内部関数が混ざる場合にカオス、というのはわかるけれど(クラスの場合スコープが限定される・・・けれども結局はグローバル空間を考えなきゃいけないわけで同じだよね???)、今でもコンパイラの効率ってのはそこまで気にしなければいけないものなのかな
- 技術的な問題。逃げた(とは書いてませんが・・・)
8.2.1 Kinds of declarations
変数とか定数とか関数とか名前空間とかクラスとかテンプレートとか。
8.2.2 Variable and constant declarations
- 変数で宣言するもの: 名前、型、(オプションで)初期化値
- さりげなくまた自著の宣伝 ^^;
- 定数も一緒。 const つけるだけ。
- 定数の場合、初期化値が必須
- 変数でもなるべくなら初期化をつける習慣づけを。初期化漏れはバグの温床
- まあ最近は大抵はコンパイラが怒ってくれます
- 故意にやる事は無いだろうけれど、こういうミスはよくあります。ので習慣にすべし、と。
-
- 指に覚えさせろ、というやつですね
- 繰り返しですが、こういう「アホですか」ミスは疲れてるときとか忙しいときに起こります。必ず初期化。習慣にしてください。
-
8.3 Header files
- 宣言だとか定義の管理をどうするか?
- 何百もの宣言を毎回ソースに入れるのですかそうですか? しかも他人が書いた奴までコピペですかそうですか?
- というわけで分離しましょうと。
- C系統ではヘッダファイルですね。よく*.hが使われます。これに宣言を全て入れておいて、実装はcppファイルで。
- 拡張子 .h は必須じゃなくなんでもいいんですが(実際標準ライブラリはそうなってませんし、boostなんぞhppですね)けれども、いくつかのコンパイラおよび、多くの統合環境とかではそれを前提としている場合があります。
- #include がやっているのは単にその場所に指定されたファイルを展開しているだけなので、実はヘッダの位置じゃなく、どこでも使えます。配列の内容定義とかで使っている邪悪な例をいくつか・・・
- includeはコンパイル前に起こるのでpre-processingとも。
- ヘッダは実装者と利用者でおなじものを使うのに意味がある。一貫性チェックになる。
- これにテストコードをつけると検証可能な仕様書のできアガリなわけですね
- ヘッダは実装者と利用者でおなじものを使うのに意味がある。一貫性チェックになる。
- ヘッダファイルは多数のソースからインクルードされるので、複数ファイルに存在しても良い宣言のみを入れること
- 関数宣言、クラス宣言、数値定数などの定義
8.4 Scope
- スコープとはプログラムテキストのある領域のこと
- 変数や定数などの名前は、宣言されたところから有効(in scope)でスコープを出たところで無効になる
- スコープはネストの内側まで届くので、 {{{の中からでも外見えますよー}}}
- スコープは名前の衝突を防ぐため
- 大きい順に
- global scope
- namespace scope
- class scope
- local scope
- statement scope
-
- statementスコープってなんだ?と思ったらfor (int i = ...)のスコープのことらしい local scopeの一種だと思い込んでたよ。たしかに {}なしでもスコープもつものね。
- グローバルいうな! は結局犯人の特定が難しくなるからなわけで、あなたが名探偵なら問題ないわけですね
- nested block についてはCの時にはブロック単位でしかスタックフレームの構築(というかローカル変数)ができなかったので必要だったと思うのですが、C++になってから何か意味あんの? というのがわかりません
8.5 Function call and return
- 手続きの抽象化・関数化。名前つけるだけの意味がある手続き・動作があったら関数化
- c++の要素として、結果を出す演算、と、その順番を決める制御文があるけれど、これらをひとつにまとめるものが関数
8.5.1 Declaring arguments and return type
まあそのまんま特に書くこともないんだけど
- 宣言でも定義でも引数の宣言時に名前をつけるのは任意。どっちでもイイ。
というのが、あー定義でもなのかー、と驚いた。何に使うんよ、と思ったら
- 例えば myfind(vector
vs, string s, int hint) とかいう関数があったとして、このhint情報で大体の位置を教えてあげることでパフォーマンスアップする事になっていたとする - しかし実際に使ってみるとほとんどのコードでこのhintは使われていない。こうなるともう単なるダメ機能なので削りたい
- すでに多数のコードがこのhintがある物としてコーディングされてしまっているのでI/Fは変えたくない。
というようなとき、単純にこのhintを使わなくすればいいんだけど、こんな時に最後の引数を intだけにしておく、というような使い方ができるらしい。
-
- ええっこれが何の役に??? というと1つは間違いなくこの値を使ってない(アクセスのしようがないんだから)、という保証ができる事と、うるさい警告を黙らせる事に成功することくらいか。
Buddha:~ tkuro11$ g++ -Wunused-parameter unused_and_named.cpp pppp.cpp:4: warning: unused parameter ‘c’ Buddha:~ tkuro11$ g++ -Wunused-parameter unused_but_not_named.cpp Buddha:~ tkuro11$
-
- おおおおおお、ウォーニング消えたぞー
- 誰がつけるんだこんなスイッチ・・・
- おおおおおお、ウォーニング消えたぞー
8.5.2 Returning a value
これもなんのこっちゃな節。
- 戻り値ある関数はちゃんと返しましょうね、とか。 if がこんがらかっているとなかなかにハードになるかも
- Tと宣言してあって、ある型Vで返した場合、初期化と同じ事が起きる
- main()は歴史的理由で 何も書いてない場合は 0 が返る、とか
そりゃそうだよなー、と言う話。
8.5.4 Pass-by-const-reference
- でかい vector返そうとしたら???
- 数百MBの構造を関数呼ぶたびにコピーってどうなんよ
- というわけでポインタ・・・
- ではなくて 参照 を使いましょう
- それも constです。これは。。。良いものだ
- みつけにっくいバグというのは基本的に 嫁無い、見栄無い コード(ん?)なわけで、constで切り分けておけば嫁無くとも見栄無くとも大丈夫なのでがんばりましょう(?)
8.5.5 Pass-by-reference
うきゃークドい
- 初期化関数なんかでは結構参照先を書き換えるケースも出てくるよね。という話
- 参照は複雑な式の aliasとしてもつかえますよーとか。
- 関数型の let みたいですね
- 気をつけないとわかめなバグの大量生産ですごめん
- ありがちなんだけど swap()とかの話
- stdlibにもあるよーって
8.5.6 Pass-by-value vs. pass-by-reference
- pass-by-value , pass-by-reference, pass-by-const-referenceの三つ巴
- いつ、どれ、つかう?
- 小さいオブジェクトなら value
- でかいオブジェクトなら const-reference
- どうしても書き換えたい時だけ reference
- 普通は戻り値を使いましょう
- しかしここで値を変えるとは?
- 副作用系:呼び出し元の値を変える?
- テンポラリ系:単に一時記憶として値を変える?
- rvalue, lvalueの話, referenceは lvalueを要求するが(locateが必要なので)、 const refはlvalueじゃなくても良い
- ただし、その場合一時オブジェクトができちゃうのでそのつもりで
8.5.7 Argument checking and conversion
- 引数を渡す際には必ず初期化が行われる
- その際に暗黙の変換が怒ってしまう事があるので注意、という話
- double -> int とかダウン方向の場合は明示的にコードに書くべき
- それが他人が読む事を前提にコードを書くプロの姿勢だ