Skip to content
Update cpp authored by umaumax's avatar umaumax
[[_TOC_]]
## コーディング時の注意事項
* [CERT C コーディングスタンダード 00\. はじめに]( https://www.jpcert.or.jp/sc-rules/00.introduction.html )
* [Google C\+\+ Style Guide]( https://google.github.io/styleguide/cppguide.html )
* [CERT C コーディングスタンダード 00. はじめに](https://www.jpcert.or.jp/sc-rules/00.introduction.html)
* [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
### 関数の出力
[Google C\+\+ Style Guide -Inputs_and_Outputs]( https://google.github.io/styleguide/cppguide.html#Inputs_and_Outputs )
[Google C++ Style Guide -Inputs_and_Outputs](https://google.github.io/styleguide/cppguide.html#Inputs_and_Outputs)
* 基本的に戻り値を利用すること
* どうしても引数にする場合
......@@ -16,48 +18,57 @@ e.g. `void Foo(const string &in, string *out);`
なお,入力としてポインタの情報が欲しい場合や`nullptr`である可能性がある場合には,`const T*`を利用しても良い(これは出力に`T&`ではなくポインタを利用するメリットの1つでもある)
[C\+\+ Core Guidelines: The Rules for in, out, in\-out, consume, and forward Function Parameter \- ModernesCpp\.com]( https://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters )
では,`out`なケースは単独でも複数でも返り値として返す方法を採用し,`in-out`の場合はnon-const reference(`T&`)を採用している
[C++ Core Guidelines: The Rules for in, out, in-out, consume, and forward Function Parameter - ModernesCpp.com](https://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters) では,`out`なケースは単独でも複数でも返り値として返す方法を採用し,`in-out`の場合はnon-const reference(`T&`)を採用している
* [void foo\(T& out\) \- How to fix output parameters]( https://foonathan.net/2016/10/output-parameter/ )
* [Input\-output arguments: reference, pointers or values? · Mathieu Ropert]( https://mropert.github.io/2018/04/03/output_arguments/ )
* [void foo(T& out) - How to fix output parameters](https://foonathan.net/2016/10/output-parameter/)
* [Input-output arguments: reference, pointers or values? · Mathieu Ropert](https://mropert.github.io/2018/04/03/output_arguments/)
個人的には
* ポインタ利用: null pointerチェックがあるので,面倒であるし,バグの温床
* リファレンス利用: 呼び出し側で初期化忘れ防止の初期値が無駄になり,関数内でエラーでの早期returnのときに値を初期値にするのかという問題がでてくる
* 返り値で返す: 実はgoogle coding styleにも合致する方法で,良いとこどりなのではないか?
### 注意点が多く記述されているFAQ
[C\+\+ FAQ]( https://isocpp.org/wiki/faq )
[C++ FAQ](https://isocpp.org/wiki/faq)
### クラスのstaticフィールドの利用方法
[C\+\+の class template を使えば static メンバの実体がヘッダファイルに書けるカラクリ \- higepon blog]( https://higepon.hatenablog.com/entry/20100803/1280834422 )
[C++の class template を使えば static メンバの実体がヘッダファイルに書けるカラクリ - higepon blog](https://higepon.hatenablog.com/entry/20100803/1280834422)
#### 定数値をhppではなく、cppファイルに記述する方法
[explicit-define-static-data-mems \- Constructors, C\+\+ FAQ]( https://isocpp.org/wiki/faq/ctors#explicit-define-static-data-mems )
`std::string`はこちら
[c\+\+ \- Static constant string \(class member\) \- Stack Overflow]( https://stackoverflow.com/questions/1563897/static-constant-string-class-member )
[explicit-define-static-data-mems - Constructors, C++ FAQ](https://isocpp.org/wiki/faq/ctors#explicit-define-static-data-mems)
`std::string`はこちら [c++ - Static constant string (class member) - Stack Overflow](https://stackoverflow.com/questions/1563897/static-constant-string-class-member)
#### 定数値をhpp、cppファイルに宣言を記述する方法
[static-const-with-initializers \- Constructors, C\+\+ FAQ]( https://isocpp.org/wiki/faq/ctors#static-const-with-initializers )
[static-const-with-initializers - Constructors, C++ FAQ](https://isocpp.org/wiki/faq/ctors#static-const-with-initializers)
### `__`(ダブルアンダースコア)は変数のどこにあっても違反
[syntax \- Why do people use \_\_ \(double underscore\) so much in C\+\+ \- Stack Overflow]( https://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c )
[syntax - Why do people use \_\_ (double underscore) so much in C++ - Stack Overflow](https://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c)
## C++17
* [variant - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/variant/variant.html)
* [optional - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/optional/optional.html)
上記は、[sewenew/redis-plus-plus: Redis client written in C++](https://github.com/sewenew/redis-plus-plus)にて活用されている
### 🔥directory_iterator(ファイルの走査順序は未規定)
### :fire:directory_iterator(ファイルの走査順序は未規定)
* [directory_iterator - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/filesystem/directory_iterator.html)
* [std::directory_iterator に注意せよ](https://zenn.dev/enchan1207/articles/29de772131de13)
## 終了時のエラー回避のために
### 基底クラスが派生クラスのリソースへ依存している際の解放順番に注意
継承でスレッドを利用している例
```cpp
#include <chrono>
#include <iostream>
......@@ -137,6 +148,7 @@ Base destructor
```
### フィールドメンバがスレッド経由でクラスのリソースへ依存している際の解放順番に注意
```cpp
#include <chrono>
#include <functional>
......@@ -217,13 +229,15 @@ Worker destructor
```
## 継承
public, protected, privateの3種類の継承があるが,通常はpublic継承を利用するので,あまり気にする場面はないと思われる
[非public継承の使いどころ \| 闇夜のC\+\+]( http://cpp.aquariuscode.com/inheritance-use-case )
public, protected, privateの3種類の継承があるが,通常はpublic継承を利用するので,あまり気にする場面はないと思われる [非public継承の使いどころ | 闇夜のC++](http://cpp.aquariuscode.com/inheritance-use-case)
### 抽象クラスを利用するときには、ポインタとして利用する
抽象クラスはインスタンス化できない
### コンストラクタ/デストラクタの呼び出し順序
```cpp
#include <iostream>
......@@ -271,6 +285,7 @@ Base destructor
```
`Base``virtual`を外した場合の挙動
```bash
$ ./a.out
Base constructor
......@@ -280,7 +295,8 @@ Base destructor
```
### `virtual`は伝播するので、継承先で明記しなくてもよい
[virtual function specifier \- cppreference\.com]( https://en.cppreference.com/w/cpp/language/virtual )
[virtual function specifier - cppreference.com](https://en.cppreference.com/w/cpp/language/virtual)
```cpp
#include <iostream>
......@@ -304,6 +320,7 @@ int main() {
```
## enum
よく使う命名例
```cpp
......@@ -311,23 +328,29 @@ enum Error { kSuccess, kInvalidArgs };
```
## 構造体
### 構造体/クラスのフィールドのコロンで参照bit範囲を設定できる
[c\+\+ \- ":" \(colon\) in C struct \- what does it mean? \- Stack Overflow]( https://stackoverflow.com/questions/8564532/colon-in-c-struct-what-does-it-mean )
[c++ - ":" (colon) in C struct - what does it mean? - Stack Overflow](https://stackoverflow.com/questions/8564532/colon-in-c-struct-what-does-it-mean)
* そのフィールドにそれ以上の値を定数で代入すると、ビルド時に警告がある
* 超えた範囲は巡回する(参照bit範囲が固定なので、このように見えるだけでは?)
* 実行時にも有効で、`int v:2;`とすると、`-2,-1,0,1`の値のみを取る
## 関数
### `f(g(x), h(y))`の呼び出し順序は規定されていない
ちなみに、Rustは最近、left-to-rightであることが規定された
## ラムダ関数
* ラムダ関数のキャプチャについて`[&]`は利用しないこと
* 基本的には、`[hoge]`としてコピーするか、引数としする方法を取り、どうしても、参照のキャプチャをしたい場合には明示的に、変数名を指定して`[&hoge]`の形式を利用すること
* `[&this]`はできないので、`[this]`となる
### ローカル変数のキャプチャの遅延実行
* ローカルな変数をキャプチャして他のスレッドに渡して遅延実行はNG
* ダングリングポインタを参照することになり、直後に再帰関数などを呼ぶとスタックの内容が書き換わりやすい
* スレッドごとに、スタックが独立しているので、スレッドによって、破壊の傾向が変化することもある
......@@ -339,7 +362,8 @@ enum Error { kSuccess, kInvalidArgs };
* 問題がある挙動になって初めて検出されるので、存在しないことの証明ができない
### パフォーマンス
[関数ポインタと関数オブジェクトのインライン展開 \- Qiita]( https://qiita.com/kaityo256/items/5911d50c274465e19cf6 )
[関数ポインタと関数オブジェクトのインライン展開 - Qiita](https://qiita.com/kaityo256/items/5911d50c274465e19cf6)
関数オブジェクト、関数ポインタ、ラムダ関数の順に遅くなる(この場合、関数ポインタを利用しても速度が同じとなっている)
......@@ -362,6 +386,7 @@ Benchmark #1: ./a.out
```
## 型
### unsigned char型またはunsigned short型などの演算結果はsigned int型となる
```cpp
......@@ -449,17 +474,19 @@ int main(int argc, char* argv[]) {
bool type is b
~bool type is i
```
## template
### インスタンス化
例えば、テンプレートを明示的にインスタンス化して実装をcpp側にすることで、通常の関数のように扱うテクニックがある
* [テンプレートのインスタンス化 | Programming Place Plus C++編【言語解説】 第21章](https://programming-place.net/ppp/contents/cpp/language/021.html)
* [[C++]特殊化?実体化??インスタンス化???明示的????部分的????? - 地面を見下ろす少年の足蹴にされる私](https://onihusube.hatenablog.com/entry/2020/01/24/183247)
### 関数の戻り値のテンプレート
ユーザに戻り値を決定させたい場合に、明示的に指定する箇所を最低限にしたい場合は最初に返り値の型を指定させるようにするとよい
```cpp
......@@ -472,6 +499,7 @@ sum<int>(1, 2);
```
### 後置の戻り値の型と型変換
パラメータが検出されるまで,変数は存在しないため,戻り値の型を後置にしなければならない
```cpp
......@@ -483,10 +511,11 @@ auto func(I beg, I end) -> decltype(*beg) {
```
## 参照
### `&`付きの型に対して,自由に値を代入したい
* [C\+\+ \- 参照の初期化を条件分岐で行う方法について|teratail]( https://teratail.com/questions/158884 )
* [std::vector で参照を保持したい \- Secret Garden\(Instrumental\)]( http://secret-garden.hatenablog.com/entry/2015/08/28/000000 )
* [C++ - 参照の初期化を条件分岐で行う方法について|teratail](https://teratail.com/questions/158884)
* [std::vector で参照を保持したい - Secret Garden(Instrumental)](http://secret-garden.hatenablog.com/entry/2015/08/28/000000)
```cpp
#include <functional>
......@@ -514,20 +543,25 @@ int main(int argc, char* argv[]) {
```
## new
### placement new
[『placement new』自分でメモリを管理してみしょう \| GAMEWORKS LAB]( http://gameworkslab.jp/2020/01/28/%E3%80%8Eplacement-new%E3%80%8F%E8%87%AA%E5%88%86%E3%81%A7%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E7%AE%A1%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%81%97%E3%82%87%E3%81%86/ )
[『placement new』自分でメモリを管理してみしょう | GAMEWORKS LAB](http://gameworkslab.jp/2020/01/28/%E3%80%8Eplacement-new%E3%80%8F%E8%87%AA%E5%88%86%E3%81%A7%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E7%AE%A1%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%81%97%E3%82%87%E3%81%86/)
#### コンストラクタは自動的に呼ばれる
#### デストラクタは明示的に呼び出す必要がある(deleteを呼んではならない)
[c\+\+ \- why destructor is not called implicitly in placement new"? \- Stack Overflow]( https://stackoverflow.com/questions/1022320/why-destructor-is-not-called-implicitly-in-placement-new )
[c++ - why destructor is not called implicitly in placement new"? - Stack Overflow](https://stackoverflow.com/questions/1022320/why-destructor-is-not-called-implicitly-in-placement-new)
## main関数
[implementation-defined](https://en.cppreference.com/w/cpp/language/main_function)
> A very common implementation-defined form of main() has a third argument (in addition to argc and argv), of type char*[], pointing at an array of pointers to the execution environment variables.
> A very common implementation-defined form of main() has a third argument (in addition to argc and argv), of type char\*\[\], pointing at an array of pointers to the execution environment variables.
`envp`は処理系定義
```cpp
int main(int argc, char *argv[], char *envp[]) { }
```
......@@ -535,23 +569,28 @@ int main(int argc, char *argv[], char *envp[]) { }
FYI: [\`main\` function and command-line arguments (C++) | Microsoft Docs](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170#the-envp-command-line-argument)
## デバッグ
### `__PRETTY_FUNCTION__`
[事前定義識別子\_\_func\_\_ \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/lang/cpp11/func.html )
[事前定義識別子\__func_\_ - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/lang/cpp11/func.html)
GCCの言語拡張で、名前空間名、クラス名、戻り値やパラメータといった情報も含む関数の文字列となる
## std::offstream
### error handling
* [c\+\+ \- Error handling in std::ofstream while writing data \- Stack Overflow]( https://stackoverflow.com/questions/28342660/error-handling-in-stdofstream-while-writing-data )
* [c\+\+ \- Get std::fstream failure error messages and/or exceptions \- Stack Overflow]( https://stackoverflow.com/questions/839644/get-stdfstream-failure-error-messages-and-or-exceptions )
* [c++ - Error handling in std::ofstream while writing data - Stack Overflow](https://stackoverflow.com/questions/28342660/error-handling-in-stdofstream-while-writing-data)
* [c++ - Get std::fstream failure error messages and/or exceptions - Stack Overflow](https://stackoverflow.com/questions/839644/get-stdfstream-failure-error-messages-and-or-exceptions)
__`write`したあとに`flush`して、初めて書き込みが実際に行われて、エラーがどうかがわかる__
**`write`したあとに`flush`して、初めて書き込みが実際に行われて、エラーがどうかがわかる**
例えば、`cgroup``cpu`への`tasks`ファイルへ書き込む際には、書き込むPID,TIDの設定(e.g. スケジューリング)に依存して、エラーとなる可能性があり、書き込む内容に依存した結果となる
## `std::vector`
### 非ゼロ値で初期化したい
```cpp
std::vector<int> vec = {1, 2, 3};
vec.resize(5, 10);
......@@ -560,15 +599,18 @@ vec.resize(5, 10);
`{1, 2, 3, 10, 10}`
### 確保したバッファを削除したい
`clear()``resize(0)`もキャパシティはそのまま確保された状態になるので、`shrink_to_fit()`で切り詰めないと意図した動作にはならない
### std::remove_if
[remove\_if \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/reference/algorithm/remove_if.html )
[remove_if - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/algorithm/remove_if.html)
削除する要素を詰めて、サイズが縮んだコンテナの新しい終端イテレータを返す仕様であり、要素は削除されないので、サイズは変わらない
### コピーしたい場合
[std vector C\+\+ \-\- deep or shallow copy \- Stack Overflow]( https://stackoverflow.com/questions/11348376/std-vector-c-deep-or-shallow-copy )
[std vector C++ -- deep or shallow copy - Stack Overflow](https://stackoverflow.com/questions/11348376/std-vector-c-deep-or-shallow-copy)
* `=`: 各要素の値をdeep copyする
* もし、要素自身がポインタならば意味的にはshallow copyとなっている
......@@ -583,6 +625,7 @@ std::copy(std::begin(vec_tmp), std::end(vec_tmp), std::begin(vec));
```
### `std::vector`を関数の引数にそのまま指定できるかどうか
```cpp
#include <vector>
......@@ -604,9 +647,10 @@ int main(int argc, char* argv[]) {
```
### `std::vector<bool>`
[On vector\<bool> \-\- Howard Hinnant : Standard C\+\+]( https://isocpp.org/blog/2012/11/on-vectorbool )
* __自動でビットを利用するように最適化される__(内部的にはアロケータとして`std::allocator<bool>`が利用されている)
[On vector\<bool\> -- Howard Hinnant : Standard C++](https://isocpp.org/blog/2012/11/on-vectorbool)
* **自動でビットを利用するように最適化される**(内部的にはアロケータとして`std::allocator<bool>`が利用されている)
* 要素のポインターを取得できない
* `.data()`メソッドが実装されていない
......@@ -628,27 +672,67 @@ error: no viable conversion from '__bit_iterator<std::__1::vector<bool,
逆に,`10bit`単位の数を上記のように作成することはできなさそう
### [std::vector をがんばって高速に resize する \- Qiita]( https://qiita.com/i_saint/items/59c394a28a5244ec94e1 )
### [std::vector をがんばって高速に resize する - Qiita](https://qiita.com/i_saint/items/59c394a28a5244ec94e1)
## std::regex
### 注意点
```cpp
if (std::regex_match(std::string("str[i]"), match, re)) {}
```
第1引数はmatchで値を取り出すまで,スコープが有効でなければならないので,上記の例はNG
[regex\_match \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/reference/regex/regex_match.html )
[regex_match - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/regex/regex_match.html)
> match_results オブジェクトを引数に取る形式の場合、そのオブジェクトは引数で指定した検索対象文字列へのイテレータを保持する。
このため、検索対象文字列は本関数を呼び出した後も match_results オブジェクトを使用し終わるまで破棄されないようにする必要がある。
> match_results オブジェクトを引数に取る形式の場合、そのオブジェクトは引数で指定した検索対象文字列へのイテレータを保持する。 このため、検索対象文字列は本関数を呼び出した後も match_results オブジェクトを使用し終わるまで破棄されないようにする必要がある。
## std::shared_ptr
### shared_ptrのシンタックスシュガー
`g++ --std=c++20 -O3 main.cpp -o main`
```cpp
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptr = {};
std::cout << "ptr = {}" << std::endl;
if (ptr == nullptr) {
std::cout << "{} is null." << std::endl;
} else {
std::cout << "ptr = " << *ptr << std::endl;
}
std::cout << "ptr = make_shared()" << std::endl;
ptr = std::make_shared<int>();
if (ptr == nullptr) {
std::cout << "make_shared() is null." << std::endl;
} else {
std::cout << "ptr = " << *ptr << std::endl;
}
return 0;
}
```
`{}``nullptr`のsyntax sugarとなる
```
ptr = {}
{} is null.
ptr = make_shared()
ptr = 0
```
### std::shared_ptrでラップしても、基底クラスに継承クラスを代入可能である
### コピー代入ではなくstd::moveを利用するとパフォーマンスが改善できる
[shared_ptr - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/memory/shared_ptr.html)
> 非スレッドセーフに参照カウントを増減させる方法はない。シングルスレッドでのパフォーマンスが重要で、スレッドセーフであることによるオーバーヘッドが問題になる場合、ムーブを活用すればパフォーマンスを改善できる。
......@@ -659,12 +743,14 @@ if (std::regex_match(std::string("str[i]"), match, re)) {}
```
### ラムダ関数との組み合わせの注意点
[cpp\-examples/pitfalls/shared\_ptr at master · umaumax/cpp\-examples]( https://github.com/umaumax/cpp-examples/tree/master/pitfalls/shared_ptr )
[cpp-examples/pitfalls/shared_ptr at master · umaumax/cpp-examples](https://github.com/umaumax/cpp-examples/tree/master/pitfalls/shared_ptr)
[enable_shared_from_this - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/memory/enable_shared_from_this.html)に関連するネタ?
## `std::execution`
[実行ポリシー \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/reference/execution/execution/execution_policy.html )
[実行ポリシー - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/execution/execution/execution_policy.html)
`C++17`から有効な機能
......@@ -674,26 +760,32 @@ if (std::regex_match(std::string("str[i]"), match, re)) {}
ビジーウェイトとする場合にはこれを呼び出して明示的にCPUを明け渡すと行儀が良い
* [yield \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/reference/thread/this_thread/yield.html )
* [yield - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/thread/this_thread/yield.html)
疑問点: 通常の`sleep()`[std::this\_thread::yield \- cppreference\.com]( https://en.cppreference.com/w/cpp/thread/yield )の例のようなsleepのどちらがよい?(ケース・バイ・ケースだと思われるが,短い時間のsleepならば後者こちらの方が明示的にCPUを明け渡せるのでよいのかも)
疑問点: 通常の`sleep()`[std::this_thread::yield - cppreference.com](https://en.cppreference.com/w/cpp/thread/yield)の例のようなsleepのどちらがよい?(ケース・バイ・ケースだと思われるが,短い時間のsleepならば後者こちらの方が明示的にCPUを明け渡せるのでよいのかも)
## `std::cout`
### `std::cout`を`std::ostream`として扱いたい
[c\+\+11 \- std::ostream to file or standard output \- Stack Overflow]( https://stackoverflow.com/questions/23345504/stdostream-to-file-or-standard-output )
[c++11 - std::ostream to file or standard output - Stack Overflow](https://stackoverflow.com/questions/23345504/stdostream-to-file-or-standard-output)
```cpp
std::ostream(std::cout.rdbuf())
```
### [std::cout 乗っ取り計画 \- Qiita]( https://qiita.com/yohhoy/items/1dce1c0d19baae48ae78 )
### [std::cout 乗っ取り計画 - Qiita](https://qiita.com/yohhoy/items/1dce1c0d19baae48ae78)
`std::cout.rdbuf()`を取得して、カスタムしたものを再度、設定する手順を踏む
## std::chrono
### std::chrono::duration
`std::chrono::milliseconds(duration)``duration`の単位に`double`を利用するとわかりにくいビルドエラーとなることに注意
### std::chrono::system_clock::time_point
```cpp
#include <chrono>
#include <iostream>
......@@ -720,57 +812,58 @@ int main(int argc, char* argv[]) {
```
### `std::chrono::system_clock::now()`
実装で最終的に呼び出される`clock_gettime`は発行CPUに関わらず、共通の結果となるように見える
[c\+\+ \- Where does the time from \`std::chrono::system\_clock::now\(\)\.time\_since\_epoch\(\)\` come from and can it block if accessed from multiple threads? \- Stack Overflow]( https://stackoverflow.com/questions/46740302/where-does-the-time-from-stdchronosystem-clocknow-time-since-epoch-c/46740824#46740824 )
[c++ - Where does the time from \`std::chrono::system_clock::now().time_since_epoch()\` come from and can it block if accessed from multiple threads? - Stack Overflow](https://stackoverflow.com/questions/46740302/where-does-the-time-from-stdchronosystem-clocknow-time-since-epoch-c/46740824#46740824)
> A typical C++ standard library implementation would rely on the underlying OS system call to get the actual system clock value to construct the time_point object.
[gcc/chrono\.cc at master · gcc\-mirror/gcc]( https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B11/chrono.cc#L80 )
[gcc/chrono.cc at master · gcc-mirror/gcc](https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B11/chrono.cc#L80)
> syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &tp);
> clock_gettime(CLOCK_MONOTONIC, &tp);
> syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &tp); clock_gettime(CLOCK_MONOTONIC, &tp);
[linuxで時刻を取得する方法 \- pyopyopyo \- Linuxとかプログラミングの覚え書き \-]( https://pyopyopyo.hatenablog.com/entry/20060711/p1 )
[linuxで時刻を取得する方法 - pyopyopyo - Linuxとかプログラミングの覚え書き -](https://pyopyopyo.hatenablog.com/entry/20060711/p1)
各アーキテクチャでの実装例はGolangの実装を見ると良さそう
[Goとrdtscの謎を追う \- Qiita]( https://qiita.com/kubo39/items/4319fa243fd18acc0981 )
各アーキテクチャでの実装例はGolangの実装を見ると良さそう [Goとrdtscの謎を追う - Qiita](https://qiita.com/kubo39/items/4319fa243fd18acc0981)
[Man page of CLOCK\_GETRES]( https://linuxjm.osdn.jp/html/LDP_man-pages/man2/clock_getres.2.html )
[Man page of CLOCK_GETRES](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/clock_getres.2.html)
> CLOCK_PROCESS_CPUTIME_ID (Linux 2.6.12 以降)
> プロセス単位の CPU タイムクロック (そのプロセスの全スレッドで消費される CPU 時間を計測する)。
> CLOCK_THREAD_CPUTIME_ID (Linux 2.6.12 以降)
> スレッド固有の CPU タイムクロック。
> CLOCK_PROCESS_CPUTIME_ID (Linux 2.6.12 以降) プロセス単位の CPU タイムクロック (そのプロセスの全スレッドで消費される CPU 時間を計測する)。 CLOCK_THREAD_CPUTIME_ID (Linux 2.6.12 以降) スレッド固有の CPU タイムクロック。
`CLOCK_MONOTONIC`では、基本的にCPU間の問題は回避できているように見える
## std::map, std::unordered_map
### `[]`アクセス
存在する場合はその値を、存在しない場合はデフォルト値(デフォルトコンストラクタが存在する場合)を返すことに注意
### `insert()`
存在しない場合は追加、存在する場合は無視という挙動となることに注意
### [mapのキーにvectorが使える \- minus9d's diary]( https://minus9d.hatenablog.com/entry/20120610/1339332308 )
### [mapのキーにvectorが使える - minus9d's diary](https://minus9d.hatenablog.com/entry/20120610/1339332308)
`比較演算子`がある必要がある
### [俺のunordered\_mapがこんなにpair型をキーにできないわけがない \- Qiita]( https://qiita.com/ganyariya/items/df35d253726269bda436 )
### [俺のunordered_mapがこんなにpair型をキーにできないわけがない - Qiita](https://qiita.com/ganyariya/items/df35d253726269bda436)
`ハッシュ可能`である必要がある(第3項目に自作ハッシュ関数を定義すれば良い)
## 文字列からの数値変換 - `std::stol`
* c++
* [stol - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/string/stol.html)
* 例外を投げる
* > パラメータ idx が非 nullptr の場合、変換に使用されなかった要素のインデックス( end - str.c_str() )が格納される。
* 先頭が数字であれば例外は投げないため、この引数を指定することで、与えた文字列がすべて適切に利用されたかどうかを判定できる
* パラメータ idx が非 nullptr の場合、変換に使用されなかった要素のインデックス( end - str.c_str() )が格納される。 \* 先頭が数字であれば例外は投げないため、この引数を指定することで、与えた文字列がすべて適切に利用されたかどうかを判定できる
* c
* [Man page of STRTOL](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/strtol.3.html)
* 例外を投げない
## `std::function`
[std::function のコスト \- Kludge Factory]( https://tyfkda.github.io/blog/2020/03/04/std-function-runtime.html )
[std::function のコスト - Kludge Factory](https://tyfkda.github.io/blog/2020/03/04/std-function-runtime.html)
### `std::function::target()`
......@@ -785,7 +878,7 @@ for (int i = 0 ; i != 1000000; ++i) {
}
```
[関数ポインタ型を混在させて運用する \- C\+\+ プログラミング]( https://ez-net.jp/article/6A/su9HMTVF/wKanc4EjbZFS/ )
[関数ポインタ型を混在させて運用する - C++ プログラミング](https://ez-net.jp/article/6A/su9HMTVF/wKanc4EjbZFS/)
ラムダ関数を`target()`で取り出すうまい方法がない
......@@ -793,7 +886,7 @@ for (int i = 0 ; i != 1000000; ++i) {
直接、`==`を利用して比較してはならず、`target()`を経由する
基本的に`target()`にて、 __正しい型__ を指定できていることが前提なので,下記のような比較ではなく,どの関数を代入しているかどうかのメタ情報を管理するほうがメンテナンス性がよいと考えられる(C関数ポインタであるか,ラムダ関数であるか,`std::bind`を利用しているかなどによって,この型が変わってしまう)
基本的に`target()`にて、 **正しい型** を指定できていることが前提なので,下記のような比較ではなく,どの関数を代入しているかどうかのメタ情報を管理するほうがメンテナンス性がよいと考えられる(C関数ポインタであるか,ラムダ関数であるか,`std::bind`を利用しているかなどによって,この型が変わってしまう)
```cpp
#include <cassert>
......@@ -843,38 +936,48 @@ int main(int argc, char const* argv[]) {
```
## algorithm header
[mismatch - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/algorithm/mismatch.html)
## glibc
### glibcのソースコードの検索ページ
[bminor/glibc: Unofficial mirror of sourceware glibc repository\. Updated daily\.]( https://github.com/bminor/glibc )
[bminor/glibc: Unofficial mirror of sourceware glibc repository. Updated daily.](https://github.com/bminor/glibc)
## ヘッダ
### unistd.h
UNIx STanDard Header file
### ヘッダファイルはヘッダとソースのどちらでincludeするべき?
* [Google C\+\+ Style Guide - Include_What_You_Use]( https://google.github.io/styleguide/cppguide.html#Include_What_You_Use )
* [c\+\+ \- Including \#includes in header file vs source file \- Stack Overflow]( https://stackoverflow.com/questions/2596449/including-includes-in-header-file-vs-source-file/2596554 )
* [Google C++ Style Guide - Include_What_You_Use](https://google.github.io/styleguide/cppguide.html#Include_What_You_Use)
* [c++ - Including #includes in header file vs source file - Stack Overflow](https://stackoverflow.com/questions/2596449/including-includes-in-header-file-vs-source-file/2596554)
必要なファイルでincludeするべきである
理由の一つとしては、そのヘッダをincludeしたときに実装のみで必要となるヘッダも余計にincludeしてしまい、無駄であるから
### 余計なヘッダファイルの見つけ方
余計と思われるヘッダを減らした際に`-c`オプション付きでビルドできるかどうかを基準とする方法がある
* [include\-what\-you\-use/include\-what\-you\-use: A tool for use with clang to analyze \#includes in C and C\+\+ source files]( https://github.com/include-what-you-use/include-what-you-use )
* [include\-what\-you\-useとjenkinsでC/C\+\+プロジェクトから不要な\#includeを洗い出す \- Qiita]( https://qiita.com/tomota-tar-gz/items/985b660e8f3052a387ef )
* [include-what-you-use/include-what-you-use: A tool for use with clang to analyze #includes in C and C++ source files](https://github.com/include-what-you-use/include-what-you-use)
* [include-what-you-useとjenkinsでC/C++プロジェクトから不要な#includeを洗い出す - Qiita](https://qiita.com/tomota-tar-gz/items/985b660e8f3052a387ef)
## 初期化
* [C言語 未初期化変数の罠 \- 気まま研究所ブログ]( https://aonasuzutsuki.hatenablog.jp/entry/2018/12/21/111450 )
* [変数の初期化をサボるな,それから \-Wshadow オプションを使え \- akihiko’s tech note]( https://aki-yam.hatenablog.com/entry/20130718/1374163303 )
* [C言語 未初期化変数の罠 - 気まま研究所ブログ](https://aonasuzutsuki.hatenablog.jp/entry/2018/12/21/111450)
* [変数の初期化をサボるな,それから -Wshadow オプションを使え - akihiko’s tech note](https://aki-yam.hatenablog.com/entry/20130718/1374163303)
### 複雑な処理をした結果のconst初期化
[C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es28-use-lambdas-for-complex-initialization-especially-of-const-variables)
e.g.
```cpp
const widget x = [&] {
widget val; // assume that widget has a default constructor
......@@ -886,6 +989,7 @@ const widget x = [&] {
```
### 配列の初期化
```cpp
#include <array>
#include <iostream>
......@@ -906,6 +1010,7 @@ int main(int argc, char* argv[]) {
```
デフォルトで不定値
```bash
1920169263
1651076143
......@@ -918,16 +1023,15 @@ int main(int argc, char* argv[]) {
2
```
[Array initialization \- cppreference\.com]( https://en.cppreference.com/w/c/language/array_initialization )
[Array initialization - cppreference.com](https://en.cppreference.com/w/c/language/array_initialization)
> In C, the braced list of an initializer cannot be empty. C++ allows empty list:
> int a[3] = {0}; // valid C and C++ way to zero-out a block-scope array
> int a[3] = {}; // invalid C but valid C++ way to zero-out a block-scope array
> In C, the braced list of an initializer cannot be empty. C++ allows empty list: int a\[3\] = {0}; // valid C and C++ way to zero-out a block-scope array int a\[3\] = {}; // invalid C but valid C++ way to zero-out a block-scope array
Macで試すとCでも問題なくビルドできた
### structの初期化方法
[C\+\+における構造体の初期化 \| 株式会社きじねこ]( http://www.kijineko.co.jp/node/681 )
[C++における構造体の初期化 | 株式会社きじねこ](http://www.kijineko.co.jp/node/681)
`Hoge hoge = {};`でOK
......@@ -940,7 +1044,7 @@ struct A
A a = { };
```
> のようにすれば、すべてのデータメンバをゼロ初期化または省略時初期化(データメンバが利用者定義のコ<ンストラクタを持つクラスの場合)することができます。
> のようにすれば、すべてのデータメンバをゼロ初期化または省略時初期化(データメンバが利用者定義のコ\<ンストラクタを持つクラスの場合)することができます。\
> Cの場合は、{ } の中に少なくともひとつの初期値を記述しなければなりませんが、C++ではまったく書かなくてもOKです。
> { } による初期化にせよ、( ) による初期化にせよ、処理系によっては内部的にmemsetを呼び出していることも少なからずあります。
......@@ -948,7 +1052,8 @@ A a = { };
この場合のように,`memset()`では`double``float`など危険である
### memsetで0埋めならばたまたま想定通りになる
[浮動小数点数の内部表現\(IEEE\)]( https://www.k-cube.co.jp/wakaba/server/floating_point.html )
[浮動小数点数の内部表現(IEEE)](https://www.k-cube.co.jp/wakaba/server/floating_point.html)
```cpp
数値:0.0
......@@ -962,9 +1067,10 @@ IEEE 754の規格という前提
### newで初期化子が利用できる
[初期化子リスト \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/lang/cpp11/initializer_lists.html )
[初期化子リスト - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/lang/cpp11/initializer_lists.html)
e.g.
```cpp
#include <iostream>
#include <string>
......@@ -979,7 +1085,8 @@ int main(int argc, char* argv[]) {
```
### 文字列配列の初期化
[STR11\-C\. 文字列リテラルで初期化される文字配列のサイズを指定しない]( https://www.jpcert.or.jp/sc-rules/c-str11-c.html )
[STR11-C. 文字列リテラルで初期化される文字配列のサイズを指定しない](https://www.jpcert.or.jp/sc-rules/c-str11-c.html)
```cpp
#include <iostream>
......@@ -1004,8 +1111,9 @@ int main(int argc, char* argv[]) {
```
注意
* [Size of character \('a'\) in C/C\+\+ \- Stack Overflow]( https://stackoverflow.com/questions/2172943/size-of-character-a-in-c-c )
* [sizeof演算子にまつわるアレコレ \- Qiita]( https://qiita.com/yohhoy/items/a2ab2900a2bd36c31879 )
* [Size of character ('a') in C/C++ - Stack Overflow](https://stackoverflow.com/questions/2172943/size-of-character-a-in-c-c)
* [sizeof演算子にまつわるアレコレ - Qiita](https://qiita.com/yohhoy/items/a2ab2900a2bd36c31879)
```cpp
const char* ok_list[] = {"ab", "cd", "ef", "gh", "ij"};
......@@ -1016,26 +1124,28 @@ class Hoge {
};
```
* [c \- How to initialize a structure with flexible array member \- Stack Overflow]( https://stackoverflow.com/questions/8687671/how-to-initialize-a-structure-with-flexible-array-member )
* [DCL38\-C\. フレキシブル配列メンバには正しい構文を使用する]( https://www.jpcert.or.jp/sc-rules/c-dcl38-c.html )
* [フレキシブル配列メンバをC\+\+で \- 茂加部珈琲店]( http://mocabe.hatenablog.com/entry/2018/05/23/121706 )
* [C言語のフレキシブル配列メンバ(flexible array member)、通称struct hack \| NO MORE\! 車輪の再発明]( https://mem-archive.com/2018/08/10/post-529/ )
* [c - How to initialize a structure with flexible array member - Stack Overflow](https://stackoverflow.com/questions/8687671/how-to-initialize-a-structure-with-flexible-array-member)
* [DCL38-C. フレキシブル配列メンバには正しい構文を使用する](https://www.jpcert.or.jp/sc-rules/c-dcl38-c.html)
* [フレキシブル配列メンバをC++で - 茂加部珈琲店](http://mocabe.hatenablog.com/entry/2018/05/23/121706)
* [C言語のフレキシブル配列メンバ(flexible array member)、通称struct hack | NO MORE! 車輪の再発明](https://mem-archive.com/2018/08/10/post-529/)
* あくまでCの構文?
### `std::atomic`の初期値
* [c\+\+ \- What's the default value for a std::atomic? \- Stack Overflow]( https://stackoverflow.com/questions/36320008/whats-the-default-value-for-a-stdatomic )
* [atomic::コンストラクタ \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/reference/atomic/atomic/op_constructor.html )
* [c++ - What's the default value for a std::atomic? - Stack Overflow](https://stackoverflow.com/questions/36320008/whats-the-default-value-for-a-stdatomic)
* [atomic::コンストラクタ - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/reference/atomic/atomic/op_constructor.html)
* C++17までは不定値
* `{}`で初期化可能
* C++20からは値ゼロで初期化
### グローバル変数/スレッドローカル変数(ゼロ初期化)
[Zero initialization \- cppreference\.com]( https://en.cppreference.com/w/cpp/language/zero_initialization )
[Zero initialization - cppreference.com](https://en.cppreference.com/w/cpp/language/zero_initialization)
> For every named variable with static or thread-local storage duration that is not subject to constant initialization, before any other initialization.
下記のように、明示的に処理化されていないグローバル変数およびスレッドローカル変数はゼロ初期化されるが、明示的に初期化子を記述したほうがわかりやすい
```cpp
// global variables
double f[3]; // zero-initialized to three 0.0's
......@@ -1045,7 +1155,7 @@ std::string s; // zero-initialized to indeterminate value then default-initializ
### ローカル変数/クラスメンバー(ゼロ初期化)
[Value initialization \(since C\+\+03\) \- cppreference\.com]( https://en.cppreference.com/w/cpp/language/value_initialization )
[Value initialization (since C++03) - cppreference.com](https://en.cppreference.com/w/cpp/language/value_initialization)
```cpp
int n{}; // scalar => zero-initialization, the value is 0
......@@ -1059,9 +1169,9 @@ int* a = new int[10](); // array => value-initialization of each element the val
`float* ary = new float[1000]();``float* ary = new float[1000]{};`のアセンブリが一致した
FYI: [Aggregate initialization \- cppreference\.com]( https://en.cppreference.com/w/cpp/language/aggregate_initialization )
FYI: [Aggregate initialization - cppreference.com](https://en.cppreference.com/w/cpp/language/aggregate_initialization)
[Array initialization \- cppreference\.com]( https://en.cppreference.com/w/c/language/array_initialization )
[Array initialization - cppreference.com](https://en.cppreference.com/w/c/language/array_initialization)
```cpp
int a[3] = {0}; // valid C and C++ way to zero-out a block-scope array
......@@ -1069,30 +1179,31 @@ int a[3] = {}; // invalid C but valid C++ way to zero-out a block-scope array
```
### static変数の初期化はスレッドセーフで行われる
[ブロックスコープを持つstatic変数初期化のスレッドセーフ化 \- cpprefjp C\+\+日本語リファレンス]( https://cpprefjp.github.io/lang/cpp11/static_initialization_thread_safely.html )
> ブロックスコープを持つstatic変数の初期化は、スレッドセーフであることが規定された。
> static変数の初期化が完了するまで、他のスレッドは初期化処理の前で待機する。
[ブロックスコープを持つstatic変数初期化のスレッドセーフ化 - cpprefjp C++日本語リファレンス](https://cpprefjp.github.io/lang/cpp11/static_initialization_thread_safely.html)
> ブロックスコープを持つstatic変数の初期化は、スレッドセーフであることが規定された。 static変数の初期化が完了するまで、他のスレッドは初期化処理の前で待機する。
### グローバル変数の初期化順
[How do I prevent the “static initialization order problem”?](https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use)
* 仕様で順番は規定されていない
* 複数ファイルにまたがる場合に、順番を明確にしたい場合は関数経由の呼び出しかgccの拡張機能(`__attribute__((init_priority(101)))`)を利用する
* Mac OS Xのgccでは利用できない
[\_\_attribute\_\_\)\(\(init\_priority\(N\)\)\)\(で、C\+\+のグローバル変数の初期化順序を制御する \- memologue]( https://yupo5656.hatenadiary.org/entry/20070203/p1 )
[\__attribute_\_)((init_priority(N)))(で、C++のグローバル変数の初期化順序を制御する - memologue](https://yupo5656.hatenadiary.org/entry/20070203/p1)
> C++の規格では、コンパイル単位をまたいだグローバル変数の初期化順序は規定されていませんので、g++に責任はありません。
> この初期化順が不定な問題は、init_priority属性を使うと手軽に解決できます。
> C++の規格では、コンパイル単位をまたいだグローバル変数の初期化順序は規定されていませんので、g++に責任はありません。 この初期化順が不定な問題は、init_priority属性を使うと手軽に解決できます。
> init_priority(N)のNの部分の数字が「優先度」で、101以上、65535以下の数値を書けます。小さい数字を指定した変数が先に初期化されるようになります。
> リンカスクリプトを見る限り、「同じ優先度の変数同士の初期化順は、リンクしてみないとわからない」ことと、スクリプトに KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) が先に書かれていることから、「init_priority指定のない変数と、init_priority(65535) の変数では、後者の初期化の方が先に行われる」こともわかります。
> リンカスクリプトを見る限り、「同じ優先度の変数同士の初期化順は、リンクしてみないとわからない」ことと、スクリプトに KEEP (\*(EXCLUDE_FILE (\*crtend.o \*crtend?.o ) .ctors)) が先に書かれていることから、「init_priority指定のない変数と、init_priority(65535) の変数では、後者の初期化の方が先に行われる」こともわかります。
> init_priorityの番号による初期化順の制御は、単一の.so内、および単一の実行ファイル内でのみ効くようですね。
グローバス変数の次に、スレッドローカルな変数が初期化されることを挙動から確認
```cpp
// 1
Hoge hoge;
......@@ -1102,6 +1213,7 @@ thread_local __attribute__((init_priority(101))) Fuga fuga;
```
#### グローバル変数の初期化順(実験による観測)
どのスコープでも、同一のスコープならば、上の行が優先される
* ファイルスコープ
......@@ -1115,10 +1227,8 @@ thread_local __attribute__((init_priority(101))) Fuga fuga;
* 呼ばれたタイミング
* 関数スコープTLS
* 呼ばれたタイミング
* 関数スコープの値をどうしても早く初期化したい場合は、ファイルスコープからその関数を呼び出せば良い
* 可能な限り、早く値を初期化したい場合には`__attribute__((init_priority(101)))`を付与したファイルスコープの初期化時に、初期化したい対象を利用すればよい
* `thread_local``__attribute__((init_priority(101)))`を設定可能だが、意味がない
* `__attribute__((init_priority(101)))`は、クラスに対してかつファイルスコープの変数のみに利用可能
......@@ -1230,6 +1340,7 @@ int main(int argc, char* argv[]) {
```
#### 確実にグローバル変数の値を取得するためには、関数スコープのグローバル変数を利用すると良い
```cpp
#include <sys/types.h>
#include <unistd.h>
......@@ -1312,37 +1423,44 @@ int main(int argc, char* argv[]) {
```
## 早見表
* [IEEE 754 演算のルール \- C\+\+ の歩き方 \| CppMap]( https://cppmap.github.io/articles/ieee754-arithmetic/ )
* [C\+\+ 型特性 早見表 \- C\+\+ の歩き方 \| CppMap]( https://cppmap.github.io/articles/type-traits/ )
* [IEEE 754 演算のルール - C++ の歩き方 | CppMap](https://cppmap.github.io/articles/ieee754-arithmetic/)
* [C++ 型特性 早見表 - C++ の歩き方 | CppMap](https://cppmap.github.io/articles/type-traits/)
## ADL(Argument Dependent Lookup: 実引数依存の名前探索)
* [C\+\+ ADLとは|問題と危険性、回避方法(明示的回避と事前回避) \| MaryCore]( https://marycore.jp/prog/cpp/about-adl-avoid-adl/ )
* [Argument Dependent Lookup \| 闇夜のC\+\+]( http://cpp.aquariuscode.com/argument-dependent-lookup )
* [C++ ADLとは|問題と危険性、回避方法(明示的回避と事前回避) | MaryCore](https://marycore.jp/prog/cpp/about-adl-avoid-adl/)
* [Argument Dependent Lookup | 闇夜のC++](http://cpp.aquariuscode.com/argument-dependent-lookup)
## unnamed namespace in header file
* `.cpp`でnamespaceを定義する場合は1つであるが、ヘッダファイルの場合は複数の翻訳単位で存在することになることに注意(headerで読み込んだファイルは同一ファイル内であるとみなされるため)
* 慣例として、`detail`を利用する(`impl`, `internal`を利用する例もある)
* `detail`: [tinyformat/tinyformat\.h at master · c42f/tinyformat]( https://github.com/c42f/tinyformat/blob/master/tinyformat.h#L181 )
* `detail`: [tinyformat/tinyformat.h at master · c42f/tinyformat](https://github.com/c42f/tinyformat/blob/master/tinyformat.h#L181)
* `detail`, `impl`: boost header
* 標準ライブラリは`std::__detail::`を利用している
## 文字列
### `std::string(nullptr)`は違反
[c\+\+ \- Assign a nullptr to a std::string is safe? \- Stack Overflow]( https://stackoverflow.com/questions/10771864/assign-a-nullptr-to-a-stdstring-is-safe )
[c++ - Assign a nullptr to a std::string is safe? - Stack Overflow](https://stackoverflow.com/questions/10771864/assign-a-nullptr-to-a-stdstring-is-safe)
### null文字の扱い
* [serial port \- does read\(\) in c read null character \- Stack Overflow]( https://stackoverflow.com/questions/50625105/does-read-in-c-read-null-character )
* [serial port - does read() in c read null character - Stack Overflow](https://stackoverflow.com/questions/50625105/does-read-in-c-read-null-character)
* `read()``\0`関係なく一定バイト数読む
* [std::string の途中に null 文字が含まれている場合の処理 \- Secret Garden\(Instrumental\)]( http://secret-garden.hatenablog.com/entry/2016/04/14/004729 )
* [std::string の途中に null 文字が含まれている場合の処理 - Secret Garden(Instrumental)](http://secret-garden.hatenablog.com/entry/2016/04/14/004729)
* 問題なく表示されるが,`char*`として表示すると区切れる
* [c\+\+ \- Copy string data with NULL character inside string to char array \- Stack Overflow]( https://stackoverflow.com/questions/22907430/copy-string-data-with-null-character-inside-string-to-char-array )
* [c++ - Copy string data with NULL character inside string to char array - Stack Overflow](https://stackoverflow.com/questions/22907430/copy-string-data-with-null-character-inside-string-to-char-array)
## bit
### 10bit単位の数値
:warning: ビットフィールドの以下の性質は処理系定義であるので,移植性を考えると使うべきではないと思われる
[variables \- 10 or 12 bit field data type in C\+\+ \- Stack Overflow]( https://stackoverflow.com/questions/29529979/10-or-12-bit-field-data-type-in-c )
[variables - 10 or 12 bit field data type in C++ - Stack Overflow](https://stackoverflow.com/questions/29529979/10-or-12-bit-field-data-type-in-c)
```cpp
struct uint10_t {
......@@ -1350,9 +1468,10 @@ struct uint10_t {
};
```
これはどのような仕様? => [ビットフィールド \- cppreference\.com]( https://ja.cppreference.com/w/cpp/language/bit_field )
これはどのような仕様? =\> [ビットフィールド - cppreference.com](https://ja.cppreference.com/w/cpp/language/bit_field)
`10bit`で表現できない数値を代入しようとすると警告が出る
```
xxx.cpp:22:11: warning: implicit truncation from 'int' to bit-field changes value from 2040 to
1016 [-Wbitfield-constant-conversion]
......@@ -1363,11 +1482,12 @@ xxx.cpp:22:11: warning: implicit truncation from 'int' to bit-field changes valu
### 10bit単位のデータをバイナリにパックしたい
[c\+\+ \- Efficiently packing 10\-bit data on unaligned byte boundries \- Stack Overflow]( https://stackoverflow.com/questions/34775546/efficiently-packing-10-bit-data-on-unaligned-byte-boundries )?
[c++ - Efficiently packing 10-bit data on unaligned byte boundries - Stack Overflow](https://stackoverflow.com/questions/34775546/efficiently-packing-10-bit-data-on-unaligned-byte-boundries)?
`64bit`中の下位`40bit`を利用して`10bit`x4個と`8bit`x5個として,まとめて計算して利用しようとしても,バイト単位で演算されて離れた箇所にデータが散らばり意図通りにならない(さらに,endianの問題も発生する)ため,結果として,単純にバイトごとに無理やり演算する方法が安全となり得る
下記のコードだが,シフト演算のみを行っているため,endianは関係ない気がしてきた
```cpp
#include <bitset>
#include <cstdint>
......@@ -1497,12 +1617,13 @@ int main(int argc, char* argv[]) {
ちなみに,`Doxygen`コメントの`in`,`out`は概念上の考え方に近い?(例えば,`&`での参照渡しを考慮したときに,それ自身の値が書き換わる場合と,そのポインタが指し示す値が書き換わる場合がある)
[documentation \- Is that an in or in/out parameter? Doxygen, C\+\+ \- Stack Overflow]( https://stackoverflow.com/questions/47732665/is-that-an-in-or-in-out-parameter-doxygen-c )
[documentation - Is that an in or in/out parameter? Doxygen, C++ - Stack Overflow](https://stackoverflow.com/questions/47732665/is-that-an-in-or-in-out-parameter-doxygen-c)
## シフト演算
* :warning: 意図せずにオーバーフローを引き起こす可能性がある(特に,定数値に対して処理を行う場合 `0xFF << x`とする際に,`uint32_t`の範囲を超えてしまう可能性があり得る)
* :warning: [INT34\-C\. 負のビット数のシフトやオペランドのビット数以上のシフトを行わない]( https://www.jpcert.or.jp/sc-rules/c-int34-c.html )
* 特に,__ビット数以上のシフト__が未定義であることに注意(ビット数以上のシフトを行うことで,`0`となることを意図するような設計に注意)
* :warning: [INT34-C. 負のビット数のシフトやオペランドのビット数以上のシフトを行わない](https://www.jpcert.or.jp/sc-rules/c-int34-c.html)
* 特に,\_\_ビット数以上のシフト\_\_が未定義であることに注意(ビット数以上のシフトを行うことで,`0`となることを意図するような設計に注意)
```cpp
#include <cassert>
......@@ -1573,10 +1694,9 @@ uint64_t:8B
intのhashのinputとoutputが一致してしまう(余計な演算なしにhashの定義を満たす)ため、`std::to_string()`をかますと意図する結果が得られる
* [c++ - Why std::hash\<int> seems to be identity function - Stack Overflow]( https://stackoverflow.com/questions/38304877/why-stdhashint-seems-to-be-identity-function )
* [c++ - Why std::hash\<int\> seems to be identity function - Stack Overflow](https://stackoverflow.com/questions/38304877/why-stdhashint-seems-to-be-identity-function)
* [c++ - hash value of int is the same number - Stack Overflow](https://stackoverflow.com/questions/19734875/hash-value-of-int-is-the-same-number)
```cpp
#include <functional> // for std::hash
#include <iostream>
......@@ -1641,28 +1761,35 @@ int main() {
`...`は可変長引数であるが、直接`void*`を指定してもよい
[Variadic functions \- cppreference\.com]( https://en.cppreference.com/w/cpp/utility/variadic )
[Variadic functions - cppreference.com](https://en.cppreference.com/w/cpp/utility/variadic)
`std::unique_ptr`を利用する場合には、明示的に関数の型を記述する必要がある
## C
### `C`では,関数宣言にて`foo()`ではなく,`foo(void)`とする(`C++`では特に問題はない)
* [【C言語】引数なしの関数には void を書いた方がよいという話 \- 0x19f \(Shinya Kato\) の日報]( https://0x19f.hatenablog.com/entry/2019/04/17/213231 )
* [DCL20\-C\. 引数を受け付けない関数の場合も必ず void を指定する]( https://www.jpcert.or.jp/sc-rules/c-dcl20-c.html )
### [Cのプログラムでたまに出てくる関数内の無意味なvoid宣言の意味 \- $ cat /var/log/shin]( https://shin.hateblo.jp/entry/2013/03/13/175059 )
* [【C言語】引数なしの関数には void を書いた方がよいという話 - 0x19f (Shinya Kato) の日報](https://0x19f.hatenablog.com/entry/2019/04/17/213231)
* [DCL20-C. 引数を受け付けない関数の場合も必ず void を指定する](https://www.jpcert.or.jp/sc-rules/c-dcl20-c.html)
### [Cのプログラムでたまに出てくる関数内の無意味なvoid宣言の意味 - $ cat /var/log/shin](https://shin.hateblo.jp/entry/2013/03/13/175059)
## 実現したいことからの逆引き
### 外部コマンドを安全に実行したい
[cpp\-examples/examples/fork\-exec at master · umaumax/cpp\-examples]( https://github.com/umaumax/cpp-examples/tree/master/examples/fork-exec )
[cpp-examples/examples/fork-exec at master · umaumax/cpp-examples](https://github.com/umaumax/cpp-examples/tree/master/examples/fork-exec)
### c++のコードの概要を知りたい
[Doxygen · Wiki · umaumax / memo · GitLab](https://gitlab.com/umaumax/memo/-/wikis/Doxygen)
### vectorやmapなどのコレクションをダンプしたい
e.g. [neostream.hpp](https://gist.github.com/umaumax/9765462a4a7e85dcb52515b7921191fd)
### 標準入出力先が端末かどうかを調べたい
```cpp
#include <unistd.h>
......@@ -1680,7 +1807,8 @@ int main() {
```
## 落とし穴(pitfall)
### [cos と std::cos は別物だっていう話 \- akihiko’s tech note]( https://aki-yam.hatenablog.com/entry/20080826/1219757584 )
### [cos と std::cos は別物だっていう話 - akihiko’s tech note](https://aki-yam.hatenablog.com/entry/20080826/1219757584)
* リンクの通り,`::cos(float)``double`となっている
* `using namespace std;`の有無で挙動が変化するので注意
......@@ -1730,6 +1858,7 @@ int main(int argc, char* argv[]) {
```
x86
```log
[test case]: 0.5235987902f
float =0.523598790168762207
......@@ -1759,6 +1888,7 @@ cos(double) =0.866025396499206845 d
```
arm
```log
[test case]: 0.5235987902f
float =0.523598790168762207
......@@ -1821,7 +1951,9 @@ cos(double) =0.866025396499206845 d
```
### 暗黙的なbool変換について
`-Wall -Wextra -Wconversion`としても、warningとならない
```cpp
#include <iostream>
#include <string>
......@@ -1838,6 +1970,7 @@ int main(int argc, char* argv[]) {
```
### 暗黙的な型変換(float, double)
```bash
g++ -std=c++11 a.cpp -Wall -Wextra -Wconversion
```
......@@ -1886,10 +2019,13 @@ int main(int argc, const char* argv[]) {
```
## ファイル
### ファイルIOのベンチマーク
[c++ io benchmark](https://gist.github.com/umaumax/1bde594a831c50f0d6d21a520209aad8)
### ファイル/ディレクトリの存在確認
```cpp
#include <fstream>
#include <string>
......@@ -1899,15 +2035,16 @@ bool IsFileExist(const std::string &filename) {
return ifs.is_open();
}
```
* ファイル/ディレクトリが存在: true
* シンボリックリンクの場合はその参照先に依存
### 🌟ファイルを読みたい
* [How to read a file from disk to std::vector\<uint8\_t> in C\+\+]( https://gist.github.com/looopTools/64edd6f0be3067971e0595e1e4328cbc )
* [c++ - How to read a binary file into a vector of unsigned chars - Stack Overflow]( https://stackoverflow.com/questions/15138353/how-to-read-a-binary-file-into-a-vector-of-unsigned-chars )
### :star2:ファイルを読みたい
* __なぜか、`std::istream_iterator`を利用すると、ファイルの読み込みサイズが小さくなってしまう現象が発生した__
* __理由は`\n`をスキップして`std::vector`へ保存してしまうためである__
* [How to read a file from disk to std::vector\<uint8_t\> in C++](https://gist.github.com/looopTools/64edd6f0be3067971e0595e1e4328cbc)
* [c++ - How to read a binary file into a vector of unsigned chars - Stack Overflow](https://stackoverflow.com/questions/15138353/how-to-read-a-binary-file-into-a-vector-of-unsigned-chars)
* **なぜか、`std::istream_iterator`を利用すると、ファイルの読み込みサイズが小さくなってしまう現象が発生した**
* **理由は`\n`をスキップして`std::vector`へ保存してしまうためである**
* `std::istreambuf_iterator`には`uint8_t`は指定できない
```cpp
......@@ -1986,8 +2123,8 @@ int main(int argc, const char* argv[]) {
### ファイルをmv(rename)する
* [std::rename \- cppreference\.com]( https://en.cppreference.com/w/cpp/io/c/rename )
* [FIO10\-C\. rename\(\) 関数の使用に注意する]( https://www.jpcert.or.jp/sc-rules/c-fio10-c.html )
* [std::rename - cppreference.com](https://en.cppreference.com/w/cpp/io/c/rename)
* [FIO10-C. rename() 関数の使用に注意する](https://www.jpcert.or.jp/sc-rules/c-fio10-c.html)
移植性を考慮した場合,変更先が空ディレクトリは削除できるのでrename時にエラーが起こらないが,空ディレクトリではない場合はremoveが失敗する
......@@ -2029,6 +2166,7 @@ int main() {
```
### ディレクトリ名取得/ディレクトリのfsyncを行う例
```cpp
#include <errno.h> // strerror
#include <fcntl.h> // O_DIRECTORY, O_RDONLY
......@@ -2083,7 +2221,7 @@ int main(int argc, char* argv[]) {
`<unistd.h>`
| プリプロセッサシンボル | value |
| -------- | -------- |
|-------------|-------|
| STDIN_FILENO | 0 |
| STDOUT_FILENO | 1 |
| STDERR_FILENO | 2 |
......@@ -2094,10 +2232,11 @@ int main(int argc, char* argv[]) {
`open()`してから`unlink()`することで,削除し忘れを防ぐことができる
[ファイルを open したまま各種システムコールを呼び出すとどうなるか \| ゴミ箱]( https://53ningen.com/file-open-rename-unlink/ )
[ファイルを open したまま各種システムコールを呼び出すとどうなるか | ゴミ箱](https://53ningen.com/file-open-rename-unlink/)
### `close(2)`
[【C言語】close\(\)失敗時にリトライするのは危険という話 \- Qiita]( https://qiita.com/_ydah/items/c5f6b42dbfb88c2fae1f )
[【C言語】close()失敗時にリトライするのは危険という話 - Qiita](https://qiita.com/\_ydah/items/c5f6b42dbfb88c2fae1f)
### ファイルをseekして使い続ける例
......@@ -2105,6 +2244,7 @@ int main(int argc, char* argv[]) {
ofs.clear();
ofs.seekg(0, std::ios::beg);
```
`std::ifstream`をずっと繰り返していると、メモリリークがあるのかもしれないと考えての実験用だが,特に問題なし
```cpp
......@@ -2152,34 +2292,40 @@ int main(int argc, char *argv[]) {
```
## ODR(one definition rule)
* ヘッダに実装を記述する際に,通常の関数は`inline`を付与する必要がある
* template関数はinline不要
* ただし,特殊化されたtemplateではinlineは必要
## assert
[ERR06\-C\. assert\(\) と abort\(\) の終了動作を理解する]( https://www.jpcert.or.jp/sc-rules/c-err06-c.html )
[ERR06-C. assert() と abort() の終了動作を理解する](https://www.jpcert.or.jp/sc-rules/c-err06-c.html)
* `assert()``aboort()`を呼び出して、`SIGABRT`を送信するので、gdbで補足できる
* `NDEBUG`有効時にも、`gdb`でbacktraceを表示したい場合は`abort()`を利用すれば良い
## backtrace
[\[Linux\]\[C/C\+\+\] backtrace取得方法まとめ \- Qiita]( https://qiita.com/koara-local/items/012b917111a96f76d27c )
[\[Linux\]\[C/C++\] backtrace取得方法まとめ - Qiita](https://qiita.com/koara-local/items/012b917111a96f76d27c)
* glibc backtraceは`-ggdb3`では関数名が出力できず、`-rdynamic`を付加して動的ライブラリ化する必要があった
* 行数までは取得できない
### libunwind
```bash
# for ubuntu
sudo apt-get install libunwind-dev
```
libunwindを利用すると、`-ggdb3``-rdynamic`なしでも関数名を取得可能
Mac OS Xではclangに取り込まれているので、そのまま利用可能(`-lunwind`も不要)
see: [llvm\-project/libunwind\.h at main · llvm/llvm\-project]( https://github.com/llvm/llvm-project/blob/main/libunwind/include/libunwind.h )
Mac OS Xではclangに取り込まれているので、そのまま利用可能(`-lunwind`も不要) see: [llvm-project/libunwind.h at main · llvm/llvm-project](https://github.com/llvm/llvm-project/blob/main/libunwind/include/libunwind.h)
## clang++
### Ubuntuにてclang++で`cannot find iostream`となるときに、下記で直る
[c++ - clang++ cannot find iostream - Ask Ubuntu](https://askubuntu.com/questions/1449769/clang-cannot-find-iostream)
```bash
......@@ -2187,14 +2333,18 @@ sudo apt install -y g++-12
```
## clang-format
ヘッダのソートなどの優先順位についての例: [clang-formatで*.generated.hを勝手にソートさせない方法]( https://zenn.dev/sgthr7/articles/14271d56253e7a )
ヘッダのソートなどの優先順位についての例: [clang-formatで\*.generated.hを勝手にソートさせない方法](https://zenn.dev/sgthr7/articles/14271d56253e7a)
## switchのcase中に変数宣言をするときの注意
caseごとではなく、switch単位でスコープとなるので、switchの範囲外で予め宣言するか、case内部に明示的にブロックを設ける必要がある
* [c\+\+ \- Getting a bunch of crosses initialization error \- Stack Overflow]( https://stackoverflow.com/questions/11578936/getting-a-bunch-of-crosses-initialization-error/11578973 )
* [c\+\+ \- What are the signs of crosses initialization? \- Stack Overflow]( https://stackoverflow.com/questions/2392655/what-are-the-signs-of-crosses-initialization )
* [c++ - Getting a bunch of crosses initialization error - Stack Overflow](https://stackoverflow.com/questions/11578936/getting-a-bunch-of-crosses-initialization-error/11578973)
* [c++ - What are the signs of crosses initialization? - Stack Overflow](https://stackoverflow.com/questions/2392655/what-are-the-signs-of-crosses-initialization)
## コピーやムーブをした場合でもデストラクタが呼ばれる
```cpp
{
Hoge hoge;// コンストラクタ
......@@ -2203,32 +2353,37 @@ caseごとではなく、switch単位でスコープとなるので、switchの
}
```
[自作クラスをムーブする \- Qiita]( https://qiita.com/termoshtt/items/3397c149bf2e4ce07e6c )
[自作クラスをムーブする - Qiita](https://qiita.com/termoshtt/items/3397c149bf2e4ce07e6c)
## 実行時(共有ライブラリのロード時)に`undefined symbol: _ZTI8XXXClass(typeinfo for XXXClass)`
```cpp
class XXXClass {
virtual void foo() = 0;
};
```
ここで`=0`としない場合は実体を定義する必要がある
ビルドは問題なく通り、実行時に発覚することが問題点
たしかに、共有ライブラリを`nm`コマンドで見てみると`U`となっている
* [c\+\+ \- What is an undefined reference/unresolved external symbol error and how do I fix it? \- Stack Overflow]( https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix )
* [Undefined symbols for architecture x86\_64:の原因(複数) \| MaryCore]( https://marycore.jp/prog/xcode/undefined-symbols-for-architecture-x86-64/ )
* [c++ - What is an undefined reference/unresolved external symbol error and how do I fix it? - Stack Overflow](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix)
* [Undefined symbols for architecture x86_64:の原因(複数) | MaryCore](https://marycore.jp/prog/xcode/undefined-symbols-for-architecture-x86-64/)
## 読み物
* [UNIX上でのC\+\+ソフトウェア設計の定石 \(1\) \- memologue]( https://yupo5656.hatenadiary.org/entry/20040712/p1 )
* [UNIX上でのC\+\+ソフトウェア設計の定石 \(2\) \- memologue]( https://yupo5656.hatenadiary.org/entry/20040712/p2 )
* [UNIX上でのC\+\+ソフトウェア設計の定石 \(3\) \- memologue]( https://yupo5656.hatenadiary.org/entry/20040715/p1 )
* [UNIX上でのC\+\+ソフトウェア設計の定石 \(4\) \- memologue]( https://yupo5656.hatenadiary.org/entry/20040724/p1 )
* [UNIX上でのC\+\+ソフトウェア設計の定石 \(5\) \- memologue]( https://yupo5656.hatenadiary.org/entry/20040725/p2 )
* [UNIX上でのC++ソフトウェア設計の定石 (1) - memologue](https://yupo5656.hatenadiary.org/entry/20040712/p1)
* [UNIX上でのC++ソフトウェア設計の定石 (2) - memologue](https://yupo5656.hatenadiary.org/entry/20040712/p2)
* [UNIX上でのC++ソフトウェア設計の定石 (3) - memologue](https://yupo5656.hatenadiary.org/entry/20040715/p1)
* [UNIX上でのC++ソフトウェア設計の定石 (4) - memologue](https://yupo5656.hatenadiary.org/entry/20040724/p1)
* [UNIX上でのC++ソフトウェア設計の定石 (5) - memologue](https://yupo5656.hatenadiary.org/entry/20040725/p2)
## tips
### std::endl
`std::endl`は実行毎に出力バッファの内容を逐一flushするので、実行時オーバーヘッドを減らすため、ループの途中などflushの必要がない箇所では改行文字を使用した方が良い。
```cpp
......@@ -2238,6 +2393,7 @@ for (auto i = start; i != end; ++i) std::cout << i << '\n';
```
### std::map
`std::map`系のコンテナに対して`[]`演算子を用いて存在しないキーを参照した場合、valueをデフォルト値で初期化した上で要素を新規作成するという挙動である
### 出力用の参照渡し引数ではなく、返り値で出力を返すことが推奨される
......@@ -2248,7 +2404,9 @@ void get_pos(Pos &out_pos) {
out_pos.y = 2;
}
```
=>
=\>
```cpp
struct Pos {
int x, y;
......@@ -2264,6 +2422,7 @@ Pos get_pos() {
理想的には、RustのようにResult型を利用すると良い(ただし、デファクトスタンダードなライブラリが不明...)
### 基底クラスとなるクラスのデストラクタにはvirtualを付与すること
付与しないと継承先クラスを基底クラスへキャストしたときに呼び出されない
```cpp
......@@ -2347,10 +2506,7 @@ called base virtual animal destructor
end
```
### 🔥クラスのメンバ変数はコンストラクタ引数の順序ではなく、メンバの定義順に初期化される
### :fire:クラスのメンバ変数はコンストラクタ引数の順序ではなく、メンバの定義順に初期化される
```cpp
#include <iostream>
......@@ -2396,7 +2552,7 @@ view constructor: 0x0,0x4
view constructor: 0x0,0x1987fe3ca
```
### 🔥C++において引数の評価順は規定されておらず、評価順によって結果が変わるコードの動作は未定義である
### :fire:C++において引数の評価順は規定されておらず、評価順によって結果が変わるコードの動作は未定義である
引数で実行する関数の依存関係がなく順不同で実行されても問題がないようにすること
......
......