#author("2023-03-15T23:58:17+09:00","","") #author("2024-12-13T15:21:35+09:00","","") #topicpath ////////////////////////////////////////////////////////////////////////////// * 目次 [#pa168adc] #contents(); #ls2(Lang/C++/C++11/); ////////////////////////////////////////////////////////////////////////////// * C++11 のキーワード (取り敢えず関心のあるものだけ) [#m4713ac6] //============================================================================ ** スコープ付き enum [#enum-class] - 他の enum で定義された名前と重複しても識別できるようになる - enum をスコープ付きにするには、 ''enum'' に続いて ''struct'' または ''class'' 修飾子を付ける。 -- ここでの struct と class には、特に違いはない enum class COMMAND { IDLE, START, STOP, }; int foo() { COMMAND cmd = COMMAND::IDLE; // スコープ付きで定義した enum 値は、スコープが必要になる。 ... } //============================================================================ ** enum の基礎型の指定 [#enum-base-type] - 特に指定しない場合、スコープ付き列挙型では、int がベースとなる。 - 他の型をベースにしたい場合は、以下のように指定する: // int ではなく unsigned int を指定する場合 enum class COMMAND : unsigned int { IDLE, START, STOP, }; //============================================================================ ** for 文(範囲指定) [#for] - 書式 std::vector<int> vec = { 1, 3, 6, 7, 11, 32, 64 }; for( int val : vec ) { // 処理 } - この書式は以下に対して使用出来る -- 標準ライブラリのコンテナのように、begin(), end() を持つ -- begin(), end() の非メンバ関数を使うことが出来る - see also: [[Lang/C++/コンテナ#for_each]] コンテナの for_each 文 //============================================================================ ** for_each [#for_each] #include <vector> // for std::vector #include <algorithm> // for std::for_each std::vector<int> v = { 1, 2, 3, 4 }; std::for_each( v.begin(), v.end(), [](int& n) { m *= 5; } ); //============================================================================ ** 右辺値参照とムーブセマンティクス (move semantics) [#move_semantics] - オブジェクトをコピーではなく移動させるもの。 - C++03 までは、オブジェクトを別の変数に代入すると、コピーされることによって同じ内容のものが2つ出来ていた。右辺値参照ではコピーすることなく移動させるので、例えば対象のオブジェクトが巨大なものであっても、コピーに掛かるコストを気にしなくて良くなる。 //---------------------------------------------------------------------------- *** 一時オブジェクト [#gad0e5b3] - 関数内で生成されたオブジェクトが return で返された時、その関数が終了するとそのオブジェクトは消えてしまうことから、「一時オブジェクト」と呼ばれる。 - C++11 の std::vector では、一時オブジェクトを参照するコンストラクタが追加されている。 - 一時オブジェクトを参照する右辺値参照には ''&&'' を付ける。 - '&&' の付いた仮引数を受ける関数は、その一時オブジェクトを受け取る。 - 一時オブジェクトは評価されたらすぐに履きsれるので、多くの場面で破棄して構わないものとして扱える。 - C++11 の std::vector の右辺値参照を受け取るコンストラクタでは、一時オブジェクトが持つデータを *this に繋ぎ変えた後、一時オブジェクトが持つデータを無効にしている。 //---------------------------------------------------------------------------- *** std::move() 関数 [#ra01e123] - 使用するには <utility> を include する。 - この関数は、オブジェクトを一時オブジェクトに変換し、右辺値参照を取る関数が呼ばれるようにする。 #include <utility> std::vector<X> v1; std::vector<X> v2 = move(v1); // v1 を v2 に move する -- 上記の例では、move 元となった v1 は move 後に無効となる。 //---------------------------------------------------------------------------- *** ムーブコンストラクタとムーブ代入演算子 [#p6843151] - 自身の方の右辺値参照を仮引数に取るコンストラクタを「ムーブコンストラクタ」と呼ぶ。 - 右辺値参照を仮引数に取る代入演算子を「ムーブ代入演算子」と呼ぶ。 - これらの関数は、暗黙的に定義される。 //============================================================================ ** アライメントの指定 [#vb8529d6] //============================================================================ ** std::nullptr [#lb7c9c62] //============================================================================ ** 参照修飾子 [#re106fd3] //============================================================================ ** 移譲/継承 コンストラクタ [#rd52b5a3] //============================================================================ ** explicit な型変換演算子 [#o4c7c9aa] //============================================================================ ** ラムダ式 [#lambda] [キャプチャ] (仮引数リスト) -> 戻り値の型 { 関数の中身 }; - キャプチャ -- ラムダ式から参照するオブジェクトを指定。ラムダ式の定義されたスコープにあるオブジェクトのうちでラムダ式が参照できるのは、キャプチャで指定されたものに限られる。 -- キャプチャは以下の2種類がある --- 参照キャプチャ:オブジェクトが参照で渡される --- コピーキャプチャ:実体のコピーが渡される -- 記述方法 |~記述 |~意味 |~備考 | |[=] |全てをコピーキャプチャ。メンバ関数内の場合は this も対象となる | | |[&] |全てを参照キャプチャ | | |[hoge] |オブジェクト hoge をコピーキャプチャ | | |[&hoge] |オブジェクト hoge を参照キャプチャ | | |[=, &hoge] |オブジェクト hoge を参照キャプチャ、それ以外はコピーキャプチャ | | |[&, hoge] |オブジェクト hoge をコピーキャプチャ、それ以外は参照キャプチャ | | |[this] |メンバ関数内でλ式を記述する歳、thisポインタをコピーキャプチャする | | |[+this] |メンバ関数内でλ式を記述する歳、*thisオブジェクトをコピーキャプチャする |C++17 | - 戻り値型には auto を指定することが出来る //============================================================================ ** 属性 [#we1705b4] - noreturn -- 呼び出しても戻ってこない関数の記述に使用する [[ noreturn ]] void f(); -- noreturn 属性を指定された関数が throw を送出すれば、その関数から「戻る」ことが可能。 -- noreturn 属性を指定された関数が return 文を実行したり、関数末尾に到達して呼び出し元に戻った場合の挙動は未定義。 - carries_dependency -- 関数間でデータの依存性を伝播するために使用する -- ''詳細は要確認'' //============================================================================ ** 例外 [#w63a2c53] *** 例外クラスの使い分け [#kb44dcdd] *** 例外を送出しないことを明示する [#l975009b] *** 例外ポインタ [#b703371f] *** 入れ子の例外関連 [#if27cf02] //============================================================================ ** std::sto* --- 文字列を数値に変換する [#sto] int std::stoi( const string& str, size_t* idx = 0, int base = 10 ); int std::stoi( const wstring& str, size_t* idx = 0, int base = 10 ); long std::stol( const string& str, size_t* idx = 0, int base = 10 ); long std::stol( const wstring& str, size_t* idx = 0, int base = 10 ); unsigned long std::stoul( const string& str, size_t* idx = 0, int base = 10 ); unsigned long std::stoul( const wstring& str, size_t* idx = 0, int base = 10 ); long long std::stoll( const string& str, size_t* idx = 0, int base = 10 ); long long std::stoll( const wstring& str, size_t* idx = 0, int base = 10 ); unsigned long long std::stoull( const string& str, size_t* idx = 0, int base = 10 ); unsigned long long std::stoull( const wstring& str, size_t* idx = 0, int base = 10 ); float std::stof( const string& str, size_t* idx = 0 ); float std::stof( const wstring& str, size_t* idx = 0 ); double std::stod( const string& str, size_t* idx = 0 ); double std::stod( const wstring& str, size_t* idx = 0 ); long double std::stold( const string& str, size_t* idx = 0 ); long double std::stold( const wstring& str, size_t* idx = 0 ); //============================================================================ ** std::to_string --- 数値を文字列に変換する [#to_string] #include <string> std::string std::to_string( int val ); std::string std::to_string( unsigned int val ); std::string std::to_string( long val ); std::string std::to_string( unsigned long val ); std::string std::to_string( long long val ); std::string std::to_string( unsigned long long val ); std::string std::to_string( float val ); std::string std::to_string( double val ); std::string std::to_string( long double val ); std::wstring std::to_wstring( int val ); std::wstring std::to_wstring( unsigned int val ); std::wstring std::to_wstring( long val ); std::wstring std::to_wstring( unsigned long val ); std::wstring std::to_wstring( long long val ); std::wstring std::to_wstring( unsigned long long val ); std::wstring std::to_wstring( float val ); std::wstring std::to_wstring( double val ); std::wstring std::to_wstring( long double val ); //============================================================================ ** 正規表現での検索 [#ff98d5c1] - regex は g++4.7 では未実装なので動作しない(4.9で実装済みらしい)~ → [[Bug 53631 - [C++11] <regex> is unimplemented>https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631]] //============================================================================ ** 浮動小数点数の入力 [#o476bddb] //============================================================================ ** 日付・時刻 [#o44a5361] - #include <iomanip> //============================================================================ ** 乱数生成 [#mc805a6d] - #include <random> //---------------------------------------------------------------------------- *** std::uniform_real_distribution [#jcc6f309] - 指定された範囲の値が当確率で存在すように離散分布するクラス。 - 同じ目的で整数の乱数を得たい場合は、これの代わりに [[std::uniform_int_distribution>#std-uniform_int_distribution]] を使用する - 定義 namespace std { template <class RealType = double> class uniform_real_distribution; } - 生成 operator() //---------------------------------------------------------------------------- *** std::uniform_int_distribution [#std-uniform_int_distribution] - 指定された範囲の値が当確率で存在すように離散分布するクラス(整数庸用)。 //============================================================================ ** shared_ptr (共有ポインタ) [#shared_ptr] - std::shared_ptr - #include <memory> - 通常のポインタ同様の操作が出来る - 複数の std::shared_ptr が1つのリソースを指し示すことが出来る - 同じリソースを参照する std::shared_ptr が1つもなくなった時、そのリソースは自動的に開放される - 書式 T : shared_ptrとして使用したいclassの型とする std::shared_ptr<T> 変数名( new T() [, reset_function] ); - 例 #include <iostream> #include <memory> #include "ClassA.h" using namespace std; int main( int argc, char* argv[] ) { shared_ptr<ClassA> sp1( new ClassA ); // new したポインタから shared_ptr を構築 { shared_ptr<ClassA> sp2 = sp1; // 2つの shared_ptr で1個のリソースを参照する sp2->foo(); } // ここで sp2 が破棄され、参照している shared_ptr が1個になる sp1->foo(); // 同じ実体の foo() の2回目の呼び出し sp1->bar(); return( 0 ); } //---------------------------------------------------------------------------- *** リソース開放時の処理の指定 [#l47120f9] - リソースを開放するときの処理を指定することが出来る。 std::shared_ptr<T> 変数名( new T() [, reset_function] ); の reset_function に、リソース開放処理を行う関数を渡す。 - 例: void custom_reset( FILE * pf ) { if( pf ) { fclose( pf ); pf = NULL; } } int main( int argc, char * argv[] ) { std::shared_ptr<FILE> sp_f( fopen( "file.txt", "+w" ), custom_reset ); ... return( 0 ); } //---------------------------------------------------------------------------- *** std::shared_ptr::get() --- 組み込みポインタの取得 [#z3882f41] std::shared_ptr<ClassA> up_a1; ClassA *p_a1 = up_a1.get(); // up_a1 が持っている ClassA のリソースを指す組み込みポインタを取得 //---------------------------------------------------------------------------- *** std::make_shared() --- std::shared_ptr 構築のためのヘルパ関数 [#k8ecea9f] - この関数は内部で new を行なっており、リソース構築に失敗した場合にリソースリークを起こさない特性を持っている。 - 例 class X { public: X( int i, std::string str ) { m_i = i; m_str = str; } private: int m_i; string m_str; }; int main( int argc, char * argv[] ) { std::shared_ptr<X> px = std::make_shared<X>( 10, "aaa" ); ... return( 0 ); } //============================================================================ ** decltype [#decltype] - 与えられた式から型を取得する - 例1 int foo(); decltype(foo()) i; // i は int 型に決定される。 - 例2 template <typename T1, typename T2> auto func(T1 x T2 y) -> decltype(x + y) { return (x + y); } // このとき、 // T1, T2 が共に int → 戻り値は int // T1 が int, T2 がdouble → 戻り値は double //============================================================================ ** auto 型 [#auto-type] //---------------------------------------------------------------------------- *** auto 型の利点 [#d52199b7] - タイプ量を節約出来る - 初期化子から型推論される為、初期化が必須となっている。即ち、未初期化となることがない。 - 型推論する為、コンパイラにしか分からない型でも表現可能。 - C++14 では、λ式の仮引数にも使用可能になっている。 //============================================================================ ** unique_ptr [#unique_ptr] - std::unique_ptr - #include <memory> - std::shared_ptr と同様、リソースをデストラクタによって自動的に開放させるための class - ''コピーが出来ないようになっているため、リソースを参照しているオブジェクトが1つであることが保証される'' - C++03 までは std::auto_ptr があったが、C++11 では非推奨になった。 - 書式 std::unique_ptr<unique_ptrとして使用したいclassの型> 変数名 - 例 #include <memory> class ClassX { public: ClassX() { m_count_foo = 0; }; virtual ~ClassX() { std::cout << "Destroyed" << std::endl; }; void foo() { m_count_foo++; std::cout << "Execute foo(): " << m_count_foo << std::endl; } private: int m_count_foo; }; // 参照する unique_ptr を変更する void swap_unique_ptr( unique_ptr<ClassX> &up_src, unique_ptr<ClassX> &up_dst ) { up_dst = move( up_src ); cout << "unique_ptr is moved up_src to up_dst" << endl; } int main( int argc, char* argv[] ) { unique_ptr<ClassX> up1( new ClassX ); # unique_ptr の宣言&生成 // ↓ unique_ptr は複数箇所から参照できない。これを書くとエラーになる // unique_ptr<ClassX> up2 = up1; up1->foo(); unique_ptr<ClassX> up2; swap_unique_ptr( up1, up2 ); up2->foo(); up2 = nullptr; // これを実行した時点でリソースが開放される cout << "Terminate Program" << endl; return( 0 ); } //---------------------------------------------------------------------------- *** std::move() --- unique_ptr の移動 [#xe4070f7] - リソースを参照するオブジェクトを変更するには、 std::move() を使用する。 std::unique_ptr std::move( std::unique_ptr src ); //---------------------------------------------------------------------------- *** std::unique_ptr::get() --- 組み込みポインタの取得 [#z3882f41] std::unique_ptr<ClassX> up_x1; ClassX *p_x1 = up_x1.get(); // up_x1 が持っている ClassX のリソースを指す組み込みポインタを取得 //============================================================================ ** 複数の値から、最大値または最小値を選択する [#hfd09405] //============================================================================ ** 2つの変数を入れ替える [#s458c40d] //============================================================================ ** コンパイル時にアサーションを行う [#db4bc5bc] //============================================================================ ** 浮動小数点数の四捨五入 [#a44e97e9] //============================================================================ ** 数学関数 [#b2da218a] //============================================================================ ** std::function --- 関数オブジェクトを変数に持つ [#std-function] - #include <functional> - std::function - 関数オブジェクトや関数ポインタを変数として保持するために使用する class - 書式 戻り値型( 実引数型1, 実引数型2, ... 実引数型N ); - 例 struct ST_FOO { int operator() ( int x, int y ) const { return( x + y ); } }; int bar( int x, int y ) { return( x * y ); } // 構造体 std::function<int (int, int)> f = ST_FOO(); // 関数 std::function<int (int, int)> g = bar; // λ関数 std::function<int (int, int)> h = []( int x, int y ) -> int { return( x - y ); }; int result_f = f( 1, 2 ); std::cout << "f: " << result_f << std::endl; int result_g = g( 3, 4 ); std::cout << "g: " << result_g << std::endl; int result_h = h( 6, 5 ); std::cout << "h: " << result_h << std::endl; //============================================================================ ** 時間演算を行う [#j45d63eb] - #include <chrono> //============================================================================ ** タプル [#g6c7a34b] - #include <tuple> - 複数の異なる型の値の集合体 std::tuple<TYPE1, TYPE2,...> value(val1, val2,...); - 例 #include <iostream> #include <string> #include <tuple> using namespace std; void print_tuple( tuple<int, char, string> &t ) { cout << "1:[" << get<0>( t ) << "] 2:[" << get<1>( t ) << "] 3:[" << get<2>( t ) << "]" << endl; } int main( int argc, char * argv[] ) { tuple<int, char, string> t( 1, 'a', "Hello" ); // 値を参照する print_tuple( t ); // まとめて値を設定する t = make_tuple( 2, 'b', "World" ); // 再び値を参照する print_tuple( t ); return( 0 ); } //============================================================================ ** constexpr [#x2805515] - constexpr 指定 -- constexpr 変数:コンパイル時定数となることを指定する -- constexpr 関数:コンパイル時に計算可能となることを指定する → コンパイル時に実行出来ることを意味する - 例 constexpr int square(int x) { return x * x; } int array[square(2)]; // 配列の要素数は4 - constexpr 関数で実行できることには、言語規格毎に以下の制限がある -- C++11 で可能な操作 -- C++14 で追加で可能になった操作 -- C++20 で追加で可能になった操作 //============================================================================ ** static_assert [#static_assert] - コンパイル時にアサーションを行う - 書式 static_assert(constant-expression, string-literal); -- constant-expression : 条件式。偽 であればコンパイル時にアサーションする。 -- string-literal : アサーション時のメッセージ。 //============================================================================ ** システム終了 [#gf1533a6] //============================================================================ ** スレッド [#thread] - → [[Lang/C++/C++11/thread]] //============================================================================ ** コンテナ [#container] - → [[Lang/C++/C++11/コンテナ]] ////////////////////////////////////////////////////////////////////////////// * build (clang++/g++) [#r110442c] - コンパイラオプションに "-std=c++11" または "-std=c++0x" の追加が必要となる場合がある -- 指定し忘れた場合、以下のように本来あるはずの定義がないと怒られる: [例] clang++ の場合:shared_ptr が std に存在しないという下記のエラーが出る: clang++ -Wall -ggdb -c -o custom_deletee.o custom_deletee.C custom_deletee.C:46:8: error: no member named 'shared_ptr' in namespace 'std' std::shared_ptr<CX> spx1( new CX( 11, (char *)"test-BBBB" ), FinalizeCX ); ~~~~~^