せんとれ式C++コーディング規約(ベータ版)

*本規約は推敲中のものであり、予告なく変更されることがある

はじめに

C++は複雑な言語である。

そのすべての仕様を正しく把握し運用するのは困難である。 しかしすべての機能を使う必要はない、その代わりに必要に応じて利用者がそのサブセットを使えば良いのである。

ここでは、組込環境()での利用をターゲットとし、そのサブセットをコーディング規約として定義することを目的とする。

*特に利用可能なRAMが数KB〜1MB未満のベアメタル(OS無し)環境を想定している。ヒープメモリは利用できないか、高コストである。Raspberry Pi等の本質的にPCと大差がない環境は対象外とする

禁止 (MUST NOT)

下記のキーワードは使用不可とする。

  • アクセス指定子の private/public/protected/friend
  • 仮想関数指定の virtual
  • class
  • 例外の throw/try/catch

アクセス指定によるカプセル化はオブジェクト指向の中核をなす要素である。 しかし、本スタイルではオブジェクト指向的なアプローチを採用せす、関数型に近いアプローチを取る。 そのため、virtual や class キーワードも同様に禁止している。 (ただし、 struct に対してメンバ関数を定義するのは問題ない)

これは、組込においてはオブジェクト指向が提供する様な実行時のダイナミックな抽象化が必要なケースが少ないからである。 また、実行時抽象化を実現するにあたってはオブジェクトをヒープメモリ領域に確保するケースが多いが、組込の制限されたメモリ環境ではヒープメモリは高価な資源である。

構造体のメンバーは利用者に対してなにも隠蔽ができない。それらは関数同様のインタフェースとして注意深く設計することを推奨する。 キャッシュ変数などの利用者が意識すべきでないメンバー変数については、アクセス指定の代わりに、変数名の先頭にアンダースコア “_” をつけることを推奨する(例: “_temp”)。

同様に、利用者が注意を払うべきでないメンバー関数についても先頭に “_” を指定することを推奨する(例 “void _internalAction();”)。

C++において例外を適切に使うのは難しく、利用にあたっては多少のオーバーヘッドを許容しなければならない。 関数のエラー通知は戻り値にエラーコードを渡すなどの代替手段を取ること。

非推奨 (SHOULD NOT)

下記の機能は非推奨とし、真に必要な場合以外は使うべきではない。

  • コンストラクタ/デストラクタ/コピーコンストラクタ/ムーブコンストラクタ

コンストラクタを定義することの1番の弊害は構造体の初期化式が使用できなくなることである。 プレーンな構造体は柔軟な記述でデータメンバーを初期化することができる。 (TODO: 例を足す)

また、コンストラクタ/デストラクタを適切に実装するのは経験的に言って、難しい。 特にコンストラクタでデバイスのレジスタ等の外部資源にアクセスするのは危険で、予測できない結果を生みがちだ。

例外的に、vector クラスの様な要素数が動的に変化する様なコンテナでは初期化時のメモリ確保と変数の生存期間切れ時のメモリ解放が必要になるため、その場合には正当な理由があるのでコンストラクタ/デストラクタを使っても問題ない。

(ただし、ヒープメモリの利用については注意が必要だ。場合によっては独自のメモリ配置関数などを定義し、ヒープメモリへの配置を避けるべきかもしれない)

その他の問題点として、下記の様にtemplateにてメンバー変数に任意の型をDI(依存性注入)する場合は、コンストラクタがデータメンバの初期化の方法を知る必要が出てきてしまうので、メンバーの構造体とコンストラクタ関数の不要な結合状態が生まれてしまう。

tempate<typename T>
struct Hoge {
  T value;

  Hoge() : value(???) { // ??? の部分はどう初期化すべき?
  }
};

単に以下の様にコンストラクタ関数を削除すれば、Hoge 構造体は value の初期化手段について一切知る必要がない。

tempate<typename T>
struct Hoge {
  T value;
};

Hoge<uint8_t> hoge { .value = 0 }; // 構造体の利用者はデータメンバーの型を知っているので適切に初期化ができる。

コンストラクタによるメンバ変数初期化の代替としては、下記のいずれかの手段を推奨する。

  • void init() 等の初期化用メンバ関数
  • static Hoge newHoge() 等の構造体のインスタンスを返す static 関数

推奨 (SHOULD)

TODO:

ネーミングルール

TODO: