MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の変更点のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の変更点
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ここでは、C++11以降の変更点を記載する。<br> <br><br> == C++11の変更点 == C++11の拡張やライブラリを使用するためには、C++11に対応したコンパイラが必要になる。<br> また、コンパイラによっては、C++11の機能を使用するために、明示的にオプションで指定する必要がある。<br> <br> 以下は、コンパイルオプションの例である。<br> g++49 -std=c++11 foo.cc g++48 -std=c++11 foo.cc clang++ -std=c++11 foo.cc <br> ===== クラスの初期化 ===== C++11では、以下のようにクラスの初期化を定義できる。 <syntaxhighlight lang="c++"> #include <iostream> class C { private: int i; public: C (int ia) : i(ia) {} // ユーザ定義のコンストラクタ C () : C (123) {} // デフォルトコンストラクタ }; int main(int argc, const char *argv[]) { C c; return 0; } </source> <br> ===== コンテナクラスの初期化 ===== クラスでも初期化リストを扱えるように、std::initializer_listクラスガ追加された。<br> 従来では、std::vectorクラスは、初期化リストを指定できず、push_back()で初期化するなどのコーディングを必要としていた。<br> <syntaxhighlight lang="c++"> #include <vector> int main(int argc, const char *argv[]) { std::vector<int> v = {1,2,3}; return 0; } </source> <br> std::mapクラスであれば、std::make_pair使用して更に面倒なコーディングが必要だったが、C++11では、以下のように記述できる。<br> <syntaxhighlight lang="c++"> #include <map> #include <string> int main(int argc, const char *argv[]) { std::map<string, int> m = { {"foo",1}, {"bar",2}, }; return 0; } </source> <br> ===== x.begin() / x.end()ではなくbegin(x) / end(x)を使用する ===== <syntaxhighlight lang="c++"> #include <vector> #include <algorithm> int iarray[] = {9, 7 ,8, 1, 5}; std::vector<int> ivec = {5, 4, 0, 7, 1}; // C++98, C++03の記述方法 std::sort(&iarray[0], &iarray[0] + sizeof(a) / sizeof(a[0])); std::sort(ivec.begin(), ivec.end()); // C++11の記述方法 std::sort(begin(iarray), end(iarray)); std::sort(begin(ivec), end(ivec)); </source> <br> ===== 推論型 ===== 変数の型を推論型にすることで、プログラミングが簡単・簡素になる。<br> autoとRange-Looped forを組み合わせることでループが簡単に記述できる。<br> <br> ===== Range-Based Loop ===== 全要素に順次アクセスする場合は、Range-Based Loopを使用する。<br> <syntaxhighlight lang="c++"> // C++98, C++03の記述方法 for(std::vector<double>::iterator i = dvec.begin(); i != dvec.end(); i++) { sum += *i; } // C++11の記述方法 for(auto d : dvec) { total += d; } </source> <br> ===== constexpr ===== constexprを使用することで、以下のような初期化ができる。<br> <syntaxhighlight lang="c++"> #include <iostream> typedef struct tag_X { int n; } X int main(int argc, const char *argv[]) { constexpr X x = {123}; int a[x.n] = {1}; return 0; } </source> <br> ===== スマートポインタ ===== 従来のnew / deleteではなく、スマートポインタを使用する。<br> 詳細は、[[スマートポインタの使い方(unique ptr)]]、[[スマートポインタの使い方(shared ptr)]]、[[スマートポインタの使い方(weak ptr)]]を参照する。<br> <syntaxhighlight lang="c++"> #include <memory> std::unique_ptr<int> pihoge(new(10)); std::shared_ptr<std::string> pstrhoge(new("")); std::weak_ptr<double> pdhoge(new(5.0f)); </source> <br> ===== nullptr ===== NULLの定義が0や0Lのため、オーバーロード時の評価で期待した結果が得られない問題あり、nullptrが導入された。<br> <syntaxhighlight lang="c++"> #include <iostream> void f(double *fptr) { std::cout << __PRETTY_FUNCTION__ << std::endl; } void f(int i) { std::cout << __PRETTY_FUNCTION__ << std::endl; } int main(int argc, const char *argv[]) { f(0); // f(int) f(nullptr); // f(double*) { char *phoge1 = NULL; char *phoge2 = nullptr; if (phoge1 == phoge2) { } } return 0; } </source> <br><br> == C++14の変更点 == C++14とは、C++11のマイナーバージョンアップとラムダ式などの機能追加を行われたC++である。<br> この機能を使用するためには、C++14に対応したコンパイラ(g++、clang++等)が必要である。<br> * 2進数リテラル * 実行時サイズの配列 * 通常の関数の戻り値型の推論 * ジェネリックラムダ * 一般化されたラムダキャプチャ * constexpr関数の制限の緩和 * 変数テンプレート * 軽量コンセプト <br> ===== 2進数リテラル ===== 0bもしくは0Bのプレフィックスをつけて、数値の2進数リテラルを記述できる。<br> <syntaxhighlight lang="c++"> int i = 0b1100; // i = 12 </source> <br> ===== 実行時サイズの配列 ===== 配列のサイズ(要素数)を実行時の値で指定できるようになる。<br> <syntaxhighlight lang="c++"> void f(std::size_t size) { int a[size]; // 実行時サイズの配列 } </source> <br> C言語とは、sizeofで値が取得できない等、細かい部分で互換性がない。<br> また、クラス内で使用できない場合がある。<br> 構造体内の動的配列は、Variable Length Array In Structure(VLAIS)と呼ばれる。<br> C++14の実行時サイズ配列は、VLAISをサポートしない。<br> <syntaxhighlight lang="c++"> void f(std::size_t size) { struct { int a[size]; // GCC VLAIS, C++14 ではエラーになる } valis; } </source> <br> ===== 通常の関数の戻り値型の推論 ===== ラムダ式と同様に、通常の関数でもreturn文から戻り値の型を推論できる。<br> return文のオペランドの式から推定される。<br> <syntaxhighlight lang="c++"> auto f(); // 関数宣言では、戻り値の型は不明 auto f(){return 123;}; // 関数f()の定義で、戻り値の型はintとなる。 int x = f(); // x = 123 </source> <br> ===== decltype(auto) ===== decltype(auto)は、戻り値型の推定に追加された機能である。<br> decltype(変数)で、変数の型と同じ型を指定できる。<br> <syntaxhighlight lang="c++"> auto a = 10; // int a = 10; と同義 decltype(a) b; // int b; と同義 std::vector<decltype<a> v; // std::vector<int> v; と同義 </source> <br> ===== ジェネリックラムダ ===== ラムダ式のパラメータがジェネリックにできる。<br> <syntaxhighlight lang="c++"> [](const auto& a, const auto& b){return a > b;}; </source> <br> また、Varadic template parameter(パラメーターパック)も使用できる。<br> <syntaxhighlight lang="c++"> auto f = [](auto ... args) {}; f(); f(0); f(0,1); f(0,1,2,3,4,5); </source> <br> ===== 一般化されたラムダキャプチャ ===== 非staticデータメンバーにおいて、コピーキャプチャできる。<br> <syntaxhighlight lang="c++"> int x = 1; auto f = [y=x, &z=x] { ... }; // xをコピーしたy, xの参照をキャプチャしたz auto g = [y = x + 1] { return y; }; // 2を返す </source> <br> ムーブキャプチャも同様にできる。<br> <syntaxhighlight lang="c++"> std::unique_ptr<int> p(new int(3)); auto f = [q = std::move(p)]{/* 何か処理 */;}; </source> <br> ===== constexpr関数の制限の緩和 ===== * if, switch による条件分岐を許可 * for, while, do-while のループの許可 * void 戻り値型の許可 *: パラメータの参照で書き換えを行う * 初期化をともなう変数宣言の許可 *: static, thread_local は除く * 変数書き換えの許可 <syntaxhighlight lang="c++"> constexpr int abs(int i) { if (i < 0) { i = -i; } return i; } </source> <br> ===== 変数テンプレート ===== 変数定義にテンプレートを使用できる。<br> 詳細については、[https://kaworu.jpn.org/cpp/変数テンプレート 変数テンプレート(Variable Templates)を参照]すること。<br> <syntaxhighlight lang="c++"> template <class T> constexpr T pi = T(3.1415); template <class T> T menseki(T hankei) { return pi<T> * hankei * hankei; } </source> <br> ===== 軽量コンセプト ===== * コンセプトの軽量版 * テンプレートの型制約機能 <br> ===== 数値区切り ===== 数値区切りとは、数値リテラルを単一引用符で区切る機能である。<br> 区切りの桁は任意であり、大きな数字は、区切りを入れたほうが「人に解りやすい」というメリットがある。<br> <syntaxhighlight lang="c++"> int a = 1'000; // 千 long int b = 1'000'000; // 100万 long long int c = 1'000'000'000; // 10億 </source> <br> 2進数や16進数も区切ると見やすくなる。<br> <syntaxhighlight lang="c++"> uint16_t a = 0b11110000'00001111; // 1[byte]ずつ区切る uint32_t b = 0xff'00'ff'ff; // 1[byte]ずつ区切る </source> <br> 小数点を区切ることもできる。<br> <syntaxhighlight lang="c++"> double pi = 3.14159'26535; </source> <br> ===== 非推奨をマークする (deprecated) ===== deprecated属性は、エンティティを非推奨扱いする属性である。<br> 「非推奨扱いの名前」が使用される場合、「警告メッセージ」を出力させることができる。<br> <syntaxhighlight lang="c++"> // 非推奨の関数 [[deprecated]] char * gets(char *str); // コメント [[deprecated("gets is deprecated. Use gets_s instead.")]] </source> <br> 例えば、「非推奨の関数」はいきなり削除はできない。<br> 現実的な解として、「非推奨の関数」の実装を置き換えることが可能かもしれないが、必ずしも置き換え可能ではなく、完全な形の置き換えができるかは不明である。<br> なぜなら、実装を変更することにより、互換性の問題が発生する等、サイドエフェクトが考えられるからである。<br> 「非推奨な関数」を利用しているかどうか気付くのは難しく、C++コンパイラで警告を出し、プログラマに解決して貰う方が良い。<br> <br><br> __FORCETOC__ [[カテゴリ:C++]]
C++の変更点
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse