個人的なC++の勉強し直しメモです。内容が充実してきたら記事再構成予定。
リンクメモ
ムーブセマンティクス(C++11から)
参考になるブログ
https://yohhoy.hatenablog.jp/entry/2012/12/15/120839
https://heavywatal.github.io/cxx/speed.html
- C++では
y=x
はコピーセマンティクスを実現するシンタックスである auto_ptr
はコピーシンタックスでムーブセマンティクスを実現していたため、わかりづらくて非推奨になっている- ムーブセマンティクスは本質的には以下と同じ
1
2
3
4
5
6
7
8
9
10
11
12
int main(void) {
int* p = new int(123);
int* q;
q = p;
p = nullptr;
std::cout << *q << std::endl;
return 0;
}
Range-based for(C++11から)
auto e
は値のコピーになる。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main(void) {
std::vector<int> a = {1, 2, 3};
for (auto& e : a) {
e *= 3;
}
for (const auto& e : a) {
std::cout << e << std::endl;
}
return 0;
}
for_each(C++03でも使える)
1 |
|
std::transform
ってのもある。
Vector型のメモリ配置
- メモリ領域は連続
- 領域が足りなくなると別の箇所を再確保してコピーする
- 使用サイズの目安がわかっているなら宣言時に要素数を確保しておくほうが無駄なコピーが発生しない
1
std::vector<int> v(100); // 100が要素数
constexpr
コンパイル時定数。
Googleスタイルガイド
関数の入力用変数と出力用変数
前提として、出力用変数は可能な限り使わず、return
を用いるべきだが、
それでも出力用変数を使う場合。
- 入力用変数は全て、出力用変数より先に位置する
- 入力用変数はconst参照渡し
- 出力用変数はポインタ渡しにしておくと区別がつきやすい
1 |
|
Effective C++
宣言と定義
- 宣言:コンパイラに名前と型を知らせるもの。
- 関数のシグネチャ:仮引数の型の並び、戻り値の型
- 定義:関数やメソッドに関して言えば、その本体を与えるもの
- explicitなしで宣言されたコンストラクタは暗黙の型変換を行う。基本はexpicit付きにしておくと予想外の動作がない
1 |
|
- rhs: right hand side
- オブジェクトの値渡しでコピーコンストラクタが呼ばれる
1 |
|
1 | 1------------ |
定数文字列:
const std::string Hello("hello");
,const char* const Hello = "hello"
T* const: ポインタそのものが不変
- const T*: ポインタが指し示すデータが不変
1 |
|
- メンバ変数に
mutable
をつけるとビットレベルの不変性をもつメンバ関数からも変更できる const
なメンバ変数がある場合、コピー代入演算子は自動生成されない- コピーコンストラクタ、コピー代入演算子をprivateで宣言しておくとコピー、代入禁止にできる(定義はしない)。ただこれをやると値渡し、値返しもできないのでRVOを使った実装ができない。
- 原則としてデストラクタで例外は投げない。例外が複数同時に発生しうる。
- コンストラクタやデストラクタで仮想関数を呼ばない。ある派生クラスのコンストラクタを実行時、まず基底クラスのコンストラクタが呼ばれるがその中で仮想関数を呼んでいる場合、そこでよばれるのは派生クラスの関数ではない。
RAII(Resource Acquisition Is Initialization)
カプセル化するほど変更できる能力が増す
- privateなデータにアクセスできる関数の数は少ないほうが良い
- メンバ関数と、メンバ関数でない関数で同じことができるなら、後者のほうがよい(ここまで24項)