普段僕はプログラムを書くことが多いのですが,

use strict;
use warnings;

を頭に書くのは当然として,それでもちゃんとできているか心配になることが多々あります.

そこで,というプログラムでperlのプログラムを厳密にチェックできるということなので,最近これを使っています.perlではB::Lintというのがあります.

詳しくはB::ListのPODを読むとして,とりあえず使い方としては以下のように使います.

perl -MO=Lint,all program.pl

allというキーワードはLintにあるチェック機構をすべて適用します.つまり厳しくwarningsを吐き出すようにしています.結構,-w だけでは気づかなかったwarningsを吐き出してくれるの重宝しています.


すごくいまさらなんですが.
もう1年以上も前になるかな,GoogleのC++のスタイルガイドというのが公開されて,なかなか読む暇が無くてずっとあとで読む上体だったんだけど,昨日ちらっと読んでみたらなかなかおもしろくて寝不足なのです.

いくつか個人的におもしろかったところをピックアップするというか,忘れないためにメモっておこうと思う.

ちなみに参照したサイトは以下です.
Google C++スタイルガイド 日本語訳

インライン関数

インライン関数を定義するのは関数が小さいときのみ(10行以下)にする。

個人的にはinline関数はほとんど使わないから,このキモチがよくわからないんだよなあ.inlineにしなくてもコンパイラが結構最適化してくれることが多くて,経験上ほとんどスピードが変わらないということが多い.inlineがどういうときにもっとも有効なの
かって,まだ僕には結論を言うほどC++に詳しくないのだけれども,この件に関しては賛否両論ありそうだよなあ.僕は依然inlineは相当最適化しなけばならない時以外考えません.

コンストラクタでやるべきこと

コンストラクタでやることは簡単な初期化だけにする。もし簡単でなければ、できる限り Init() メソッドを使うこと。

定義:  コンストラクタ本体で初期化をすることができる。

賛成: 入力に好都合。クラスが初期化されているかどうかを気にする必要がなくなる。

反対: コンストラクタで初期化をするのには、いくつか問題がある。

    * 例外以外にコンストラクタがエラーになったことを知る簡単な方法がない(外を使うことは禁止されている)。
    * もし処理に失敗すると、初期化が完了していないオブジェクトが得られてしまう。このオブジェクトは不定状態になるおそれがある。
    * もしコンストラクタで仮想関数を呼び出していると、この呼び出しはサブクラス実装に対してディスパッチされない。 たとえ今のところはサブクラス化されていなくても、後になってサブクラス化したときにこの問題が入り込んでしまい、大きな問題になるおそれがある。
    * 誰かがクラス型のグローバル変数を作ってしまうと(これはルールに反しているが、それでも作ってしまった場合)、コンストラクタのコードは main() 関数よりも前に呼び出されることになる。おそらくこれは、コンストラクタのコードにとっては想定外
のことだろう。 例えば gflags はまだ初期化されていない。

結論: オブジェクトの初期化が簡単なものでなければ、明示的な Init() メソッドを用意したり、オブジェクトの初期化が成功したかどうかを示すフラグをメンバに追加するなどを検討すること。 

これはいつも悩むところ.反対派の意見にも出ているのだけれど,コンストラクタではboolを返すことができない.だから,ちょっとでも込み入ったことをするとエラーが発生する可能性があって,かつそれを検知することができない.これは正直C++のいけてないところだと思っている.僕は,結論に書いてあるように,基本的にはエラーハンドラをコンストラクタにも持たせるようにしている.複雑ならばInit()関数に任せるというのも同意だし,そうしている.基本的にはコンストラクタでやらせるのは変数の初期化のみ
ですね.

明示的なコンストラクタ
▽ 引数が1つのコンストラクタには、C++の explicit キーワードを付ける。

れは単純にやってなかったらこれからはやるようにしよう...

宣言の順序
▽ クラスにおける宣言は、次に指定した順序にする。public: は private: の前に置く、メソッドはデータメンバ(変数)の前に置くなど。
link

クラスの定義は public: セクションから始めて、protected: セクション、private: セクションという順にするべきだ。セクションが空であれば省略する。

各セクション内では通常、次の順序で宣言するべきだ。

    * typedef と enum
    * 定数
    * コンストラクタ
    * デストラクタ
    * メソッド。スタティックメソッドも含む
    * データメンバ。スタティックデータメンバも含む

気をつけないといけないのだけど,いつも手を抜いて一貫性がとれていなかった.特にこれ,という決まりはないのだけど,この際この順番で統一させるようにしようと思う.

例外
▽ C++の例外を使わない。

同意.例外だとエラーがトレースできない場合はある.独自にエラーハンドラを書いたほうが確実だと思う.

Boost
▽ Boostライブラリ群のうち許可されているライブラリだけを使う。

同意.確かにBoostは便利だし,すごく使いたくなるんだけど,移植性を考えると使わないほうが良いと思っている.個人的には公開したプログラムではBoostを使ったものは無い.ただし,googleでは以下のライブラリは許可しているらしい.要調査.

    *    Compressed Pair(boost/compressed_pair.hpp)
    * Pointer Container(boost/ptr_container)ただしシリアライゼーションを除く。
    * Array(boost/array.hpp)
    * Boost Graph Library(BGL)(boost/graph)ただしシリアライゼーションを除く。
    * Property Map(boost/property_map.hpp)
    * Iterator の一部。次のイテレータの定義に対応するもの。 boost/iterator/iterator_adaptor.hpp、 boost/iterator/iterator_facade.hpp、 boost/function_output_iterator.hpp
私たちはこの他のBoost機能をリストに追加することを積極的に検討している。そのため、このルールは将来緩和されるかもしれない。 
型名
▽ 型名は大文字で始めて、単語の頭文字を大文字にする。アンダースコアは使わない。MyExcitingClass、MyExcitingEnumなどとする。
link

あらゆる型、— クラス、構造体、typedef、enum — の名前には同じ命名規約を使う。型名は大文字で始めて、単語の先頭を大文字にするべきだ。アンダースコアは使わない。例: 

大文字で初めてキャメルケースでということですね.同意.

変数名
▽ 変数名はすべて小文字にして、単語と単語の間にはアンダースコアを入れる。クラスメンバ変数はアンダースコアで終わるようにする。例えば、my_exciting_local_variable、my_exciting_member_variable_。
link

よく使う変数名

例:

string table_name;  // OK - アンダースコアを使っている。
string tablename;   // OK - すべて小文字だ。

string tableName;   // よくない - 大文字小文字が混ざっている。

僕は変数名もキャメルケースで書いてたんだけど,確かに見分けをつけるにはアンダースコアにしたほうがいいかも.今後取り入れよう.

定数名
▽ kで始まり、大文字小文字で続ける。kDaysInAWeek
link

コンパイル時定数は、それがローカルであろうとグローバルであろうと、クラスの一部としてであろうと、どう宣言されていても、他の変数とは全然違う命名規約に従うこと。k の後に単語の先頭を大文字にして続けること。

const int kDaysInAWeek = 7;

C風に全部大文字のほうがわかりやすい気がする.目立つし.

うーん,なかなかおもしろい.結構自分は一過性を持って書いていると思っていても実は一貫性が取れていない部分が結構多い.オープンソースで開発する場合は他人に読んでもらうことが多いから一貫性に関しては特に気をはらわなければならないし,はらって
いるつもりなのだけれども.