初めに
Google C++ Style Guide
ライセンスCC-By 3.0 License
ttsukiさんの日本語訳
ライセンスCC-By 3.0 License
初回の記事
前回の記事
Google-Specific Magic
この章では、Googleがコードをより堅牢にするために使用しているトリックやユーティリティが紹介されている。
Ownership and Smart Pointers
動的確保されたオブジェクトは単一で固定された所有者(そレを行うコード)に属するようにする。その他の場所からアクセスする場合には、コピーもしくはポインタか参照を渡す方法をもいいる。
オブジェクトの所有権を移すときにはスマートポインタ(std::unique_ptr)を使用する。
所有権はなるべく共有させるべきでない。
共有する場合は、パフォーマンス上のメリットが非常に高いことと、対象のオブジェクトがconstで有ることが必要。
その際はstd::shared_ptrを使用する。
なおstd::auto_ptrの使用は禁止
cpplint
cpplint.pyを使用する。
行末に// NOLINTまたは、直前の行に// NOLINTNEXTLINEを記述することで、リンターに無視させることができる。
追記: 使用方法
cpplint.pyを作成
上のリンクのコードをコピー、貼り付け
pythonで実行
Other C++ Features
Rvalue References
右辺地参照は以下の場合に限り使用可能
- ムーブコンストラクタ、ムーブ代入演算子を定義するため
-
*thisを消費し、それ以降使用不可にするメソッドを定義するため - perfect firwardubgを実現するため
- オーバーロードの組を定義する場合
Friend
明確な理由がある場合はfriendクラス/関数は使用可能。
通常、friendに指定する対象は同じファイル内で定義する。
ただし、原則としてクラス同士のやり取りはpublicメンバを通して行う。
noexcept
有用かつ正しい場合にnoexceptを指定する。
パフォーマンスが向上する場合など。
例外を完全に無効にしている環境では条件なしnoexceptを使用する。
それ以外の場合には条件付きで使用する。
備考
Googleは既存のコードとの互換性のためにC++の例外の使用を禁止している。
この章の前にExceptionsについて説明している章があるが、例外を禁止にしている理由が互換性のためだけなので省略した。本文
Run-Time Type Information (RTTI)
実行時にオブジェクトのC++クラスを調べるRTTIで型を調べようとせずに、仮想関数を用いたり、Visitorデザインパターンなどで未然に防ぐほうが良い。
型による分岐が必要な場合は設計を変更するべきである。
Casting
static_castといったC++のキャストを使用する。
算術型の変換には{}を用いた初期化を使用する。
- (int)x // void型へのキャストのみ使用可能
+ static_cast<float>(double_value)
+ int64_t y = int64_t{1} << 42
+ T(x) // 型Tがクラスの場合は使用可能
constを外す場合はconst_cast
ポインタ型と整数型のような安全でない変換にはreinterpret_cast
ビット列を違う型として使用するときにはstd::bit_castを使用する。
Stream
シンプルかつ適切な場合に限りストリームを使用できる。
<<のオーバーロードは、その型オブジェクトが何らかの値を表す場合のみ行う。
内部状態をデバッグする目的にはDebugString()などのメンバ関数を作成した方がよい。
Preincrement and Predecrement
可能な限り、前置インクリメント/デクリメントを用いる。
Use of const
可能ならば常にconstを用いる。
加えてconstexprの方が適切な場合もある。
ただし、値渡し関数の引数では、呼び出し側に影響を与えないため、constでの関数宣言は非推奨。
Where to put the const
基本的にはconst intのように前置する形を推奨する。
Use of constexpr
定数初期化の保証にはconstexprを使用する。
非定数変数に対して定数初期化を保証するときにconstinitを使用する。
Integer Types
基本的にint型のみを使用する。
異なるサイズの整数値を使用する場合はstdint.hよりint64_tのようなサイズが厳密に定められた整数型を使用する。
また、サイズに疑問がある場合はより大きな型を使用するべき。
unsignedは、正当な理由がなければ使用禁止。
ここでの理由は、ビットパターンを表している場合や余剰によるオーバーフロー時の動作定義など。
負にならないことを示すときにはassertを使用する。
Floating-Point Types
floatとdoubleのみを使用する。
これらはIEEE-754binary32/binary64を表すものとして良い。
long doubleは環境依存なので使用不可。
Architecture Portability
環境依存のコードは書かず、移植性を確保する。
print系ではなくabsol::StrCatやstd::ostreamなど、型安全に数値型のフォーマットを行えるライブラリをしよう
する。
メモリアドレスを整数として扱う場合はuintptr_tを用いる。
...など。
Preprocessor Macro
マクロを定義しない。変わりに列挙型やconst変数を用いる。
これは、画面上のコードとコンパイラの見るコードが異なってしまうからである。
もしマクロを使用する場合には、
-
.hファイル内で定義しない - 使う直前に
#defineし、使用後すぐに#undef - 既存のマクロを置き換えず、ユニークな名前を使用する
- 関数名やクラス名を生成するために
##を使用しない
0 and nullptr/NULL
ポインタにはnullptr、文字には'\0'を使用する(0は使用しない)。
sizeof
sizeof(型)よりもsizeof(変数名)を使用する。
Type Deduction (including auto)
型推論は、可読性の大きな向上が期待できる場合と、コードが安全にできる場合に限り使用する。
Function template argument deducion
関数テンプレートの仕様は問題ない。むしろ通常の仕様方法である。
Local variable type deduction
ローカル変数の型推論は、コードをより明確にできる場合がある。
decltype(auto)は、他の方法では実装不可能な場合のみ使用する。
Return type deduction
戻り値の型推論は、その関数に含まれるreturn文の数が非常に少なく、また他のコードにより型を判断できる(シンプル)場合にのみ使用する。
ただしヘッダーファイル内の関数は戻り値の型推論を行うべきでない。
Parameter type deduction
ラムダ式の引数をautoにした場合は、呼び出しもとのコードによって型が決定される。
よって引数の型推論は、宣言と呼び出し元が十分に近く、型を用意に想像可能な場合のみに使用する。
Class Template Argument Deduction
クラステンプレートのテンプレート引数推論は明確な推論ガイドが提供されている場合にのみ使用する。
なお、std名前空間のテンプレートはすべてこれに対応しているものとする。
Designated Initializers
指示付き初期化演算子はC++20標準に順する形式でのみ使用する。
Lambda expressions
ラムダ式は匿名関数オブジェクトを作るための簡潔な手段である。
ラムダ式は以下の書式に従う。
参照キャプチャ[&]はラムダの寿命が明らかに短い場合にのみ使用する。
Template metaprogramming
複雑なテンプレートの使用は避ける。
テンプレートメタプログラミングを用いる場合、その複雑さを最小限に保ち、また適切なコメントをするなどしてコードの可読性を高めると同時に、エラーメッセージを適切に生成するようにする。
Concepts and Constraints
コンセプトは控えめに。
型トレイトと同様のコンセプトでは、コンセプトを使用する。
また、template<Concept T>よりもrequires(Concept<T>)の構文を使用する。
C++20 modules
C++20のモジュールは使用しない。
Coroutines
プロジェクト全体で共有されたコルーチンライブラリのみ使用する。
Boost
以下のライブラリを使用できる。
- Call Traits (boost/call_traits.hpp)
- Compressed Pair (boost/compressed_pair.hpp)
- The Boost Graph Library (BGL) (boost/graph) ただし、serialization (adj_list_serialize.hpp)と、 parallel/distributed algorithms and data structures (boost/graph/parallel/, boost/graph/distributed/)を除く
- Property Map(boost/property_map) ただし、parallel/distributed property maps (boost/property_map/parallel/*) を除く
- Iterator (boost/iterator)
- Polygonのうち、Voronoi diagram constructionを扱い、かつ残りのPolygonに依存していない部分 (boost/polygon/voronoi_builder.hpp, boost/polygon/voronoi_diagram.hpp, boost/polygon/voronoi_geometry_type.hpp)
- Bimap (boost/bimap)
- Statistical Distributions and Functions (boost/math/distributions)
- Special Functions (boost/math/special_functions)
- Root Finding & Minimization Functions (boost/math/tools)
- Multi-index (boost/multi_index)
- Heap (boost/heap)
- ContainerのThe flat containers (boost/container/flat_map, boost/container/flat_set)
- Intrusive (boost/intrusive)
- The boost/sort library
- Preprocessor (boost/preprocessor)
Disallowed standard library features
以下のライブラリ機能は使用禁止。
<ration><cfenv><fenv.h><filesystem>
Nonstandart Extensions
C++非標準の拡張は使用禁止。
Aliases
APIの公開で、クライアントが使用することを前提としたエイリアスのみを定義する。
名前空間へのエイリアスを公開してはいけない。
Switch Statements
列挙型以外のswitch文はdefaultチェックが必要である。
他のケースへのフォールスルーには[[fallthrough]];属性が必要。