C++ の新機能のまとめ

(スマート ポインター、いくつかのキーワード、自動型推論 auto、右辺値参照移動セマンティクスの完全転送、リストの初期化、std::function & std::bind & ラムダ式によりコールバックがより便利になり、C++11 では同時実行性が導入されました。
std::thread 関連、std
::mutex 関連、
std::lock 関連
、std::atomic 関連、
std::call_once 関連、
volatile 関連
、std::condition_variable 関連
、std::future 関連、
async 関連)

3 つの側面を要約します。1 つはより便利で、もう 1 つはより効率的で安全ですauto、for i:arr、std::function などの便利なキーワード。スマート ポインター、移動セマンティクスによる完全な転送などの効果があります。
3 つ目はスレッドのサポートです。同時実行のサポート。アトミック変数、ロック、条件変数など。結果を非同期で取得する future など、

9. スマート ポインタの問題
スマート ポインタは、動的に割り当てられたオブジェクトへのポインタを格納するために使用されるクラスで、ヒープ メモリ リークを防ぐために動的に割り当てられたオブジェクトを自動的に解放する役割を果たします。動的に割り当てられたリソースはクラスオブジェクトに引き渡されて管理され、クラスオブジェクトの宣言サイクルが終了すると自動的にデストラクタが呼び出されてリソースが解放されます。動的メモリ管理に new 演算子と delete 演算子を使用すると、プログラムの効率が向上しますが、問題が発生しやすくなります。つまり、メモリの解放を忘れたり、メモリ リークが発生したり、メモリを参照するポインタがまだ存在するときにメモリを解放したり、不正な参照が発生する メモリ ポインタ。例外が発生してメモリを解放し忘れた後、プログラムはキャッチに入ります。スマート ポインターは、R​​AII テクノロジーを使用して通常のポインターをカプセル化したものです。リソース取得は初期化」とも呼ばれる RAII テクノロジは、リソースを管理し、リークを回避するための C++ 言語の慣用句です。スタックに格納されているローカル オブジェクト (クラス) を使用して、リソースの割り当てと初期化をカプセル化し、コンストラクターでリソースの割り当てと初期化を完了し、デストラクターでリソースのクリーンアップを完了します。これにより、正しい初期化とリソースの解放が保証されます。ローカル オブジェクトはスタックに格納されているオブジェクトを指し、そのライフサイクルは手動介入なしでオペレーティング システムによって管理されます。C++11 バージョン以降に提供されるスマート ポインターは、auto_ptr、 shared_ptr、unique_ptr、weak_ptr のヘッダー ファイルに含まれています。スマート ポインター コードの実装: 2 つのクラスを使用してスマート ポインターの機能を実現します**。1 つは参照です。 1 つはカウンティング クラス、もう 1 つはポインタ クラスです。**


//  引用计数器类  用于存储指向同一对象的指针数
template<typename T>
class Counter
{
    
    
private:
	//  数据成员
	T *ptr;    //  对象指针
	int cnt;   //  引用计数器
 
	//  友元类声明
	template<typename T>
	friend class SmartPtr;
 
	//  成员函数
	//  构造函数
	Counter(T *p)   //  p为指向动态分配对象的指针
	{
    
    
		ptr = p;
		cnt = 1;
	}
	//  析构函数
	~Counter()
	{
    
    
		delete ptr;
	}
};
//  智能指针类  
template<typename T>
class SmartPtr
{
    
    
private:
	//  数据成员
	Counter<T> *ptr_cnt;  //  
 
public:
 
	//  成员函数
	//  普通构造函数  初始化计数类
	SmartPtr(T *p)
	{
    
    
		ptr_cnt = new Counter<T>(p);
	}
	//  拷贝构造函数 计数器加1
	SmartPtr(const SmartPtr &other)
	{
    
    
		ptr_cnt = other.ptr_cnt;
		ptr_cnt->cnt++;
	}
	//  赋值运算符重载函数
	SmartPtr &operator=(const SmartPtr &rhs)
	{
    
    
		ptr_cnt = rhs->ptr_cnt;
		rhs.ptr_cnt->cnt++; 增加右操作数的计数器
		ptr_cnt->cnt--; 左操作数计数器减1
		if (ptr_cnt->cnt == 0)
			delete ptr_cnt;
		return *this;
	}
	//  解引用运算符重载函数
	T &operator*()
	{
    
    
		return *(ptr_cnt->cnt);
	}
 
	//  析构函数
	~SmartPtr()
	{
    
    
		ptr_cnt->cnt--;
		if (ptr_cnt->cnt == 0)
			delete ptr_cnt;
		else
			cout << "还有" << ptr_cnt->cnt << "个指针指向基础对象" << endl;
	}
};

shared_ptr: 参照カウンタ メソッドは、複数のスマート ポインタが同じオブジェクトを指すようにするために使用されます。もう 1 つのポインタがオブジェクトを指すたびに、そのオブジェクトを指すすべてのスマート ポインタの内部参照カウントが 1 ずつ増加します。スマート ポインタが object を指すように減らされ、参照カウントが 1 減らされ、カウントが 0 になると、動的に割り当てられたリソースが自動的に解放されます。
shared_ptr の初期化:


std::shared_ptr<T> sp; //空shared_ptr,可以指向类型为T的对象
 
std::shared_ptr<int> sp(new int(5)); //指定类型,传入指针通过构造函数初始化
 
std::shared_ptr<int> sp = std::make_shared<int>(5); //使用make_shared函数初始化
 
//智能指针是一个模板类,不能将一个原始指针直接赋值给一个智能指针,因为一个是类,一个是指针
std::shared_ptr<int> sp = new int(1); //error

unique_ptr unique_ptr は、それが参照するオブジェクトを一意に所有し、特定のオブジェクトを指す unique_ptr は一度に 1 つだけ存在できます。unique_ptr を転送すると、すべての所有権がソース ポインタからターゲット ポインタに転送され、ソース ポインタは空になります。そのため、unique_ptr は通常のコピーおよび代入操作をサポートせず、STL 標準コンテナでは使用できません。ただし、戻り値は次のとおりです。ローカル変数 (コンパイラは、返されるオブジェクトが破棄されることをデバイスが認識しているため); unique_ptr をコピーすると、コピーが完了した後、2 つの unique_ptr が同じリソースを指すことになり、同じメモリが複数回解放されます。ポインターが最後にあり、プログラムがクラッシュする原因となります。
初期化: make_shared 関数はなく、new 経由でポインタのみを渡すことができます。

std::unique_ptr<T> up; //空unique_ptr,可以指向类型为T的对象,up会使用delete来释放它的指针
 
std::unique_ptr<int> up(new int(5)); //绑定动态对象

unique_ptr にはコピー コンストラクターがなく、通常のコピーおよび代入操作はサポートされませんが、ポインタの所有権をある unique_ptr から別の unique_ptr に転送する移動メカニズムが提供されます (std::move 関数を使用して、release または reset を呼び出すこともできます) )

std::unique_ptr<int> upMove = std::move(up); //转移所有权

std::unique_ptr<int> up1(new int(5));
std::unique_ptr<int> up2(up1.release()); //up2被初始化为up1原来保存的指针,且up1置为空
std::unique_ptr<int> up3(new int(6));
up2.reset(up3.release()); //reset释放了up2原来指向的内存,指向up3原来保存的指针,且将up3置为空

Unique_ptr には幅広い用途があり、関数内で動的アプリケーション リソースの所有権を返すことができ、ポインタをコンテナに保存でき、動的配列の管理をサポートします。

weak_ptrは、shared_ptr に付属する弱参照ポインタであり、通常のポインタの動作を持ちません。テンプレート クラスには、オーバーロードされた * 演算子と -> 演算子がありません。つまり、weak_ptr 型ポインタは、ヒープ メモリのポイントされたものにのみアクセスできます。それを変更できること。これは主に、shared_ptr 参照カウントの問題を解決します。循環参照が行われるとメモリ リークが発生します
weak_ptr は、shared_ptr によって管理されるオブジェクトを指します。weak_ptr をshared_ptr にバインドしても、shared_ptr の参照カウントは変わりません。メモリの一部がshared_ptrとweak_ptrによって同時に参照されている場合、すべてのshared_ptrが破棄されると、メモリを参照しているweak_ptrがまだ存在するかどうかに関係なく、メモリは解放されますしたがって、weak_ptr は、それが指すメモリが有効であることを保証しません。使用する前に、関数 lock() を使用して、weak_ptr が null ポインタであるかどうかを確認してください。
use_count() 現在のweak_ptrポインタと同じものを指すshared_ptrポインタの数を表示します。
expired() 現在のweak_ptrポインタの有効期限が切れているかどうかを確認します(ポインタが空であるか、指定されたヒープメモリが解放されています)。 lock() 現在のweak_ptrの有効期限が切れている場合、関数は空のshared_ptrポインタを返します。それ以外の場合、関数は空のshared_ptrポインタを返します
。 return a 現在のweak_ptrと同じshared_ptrポインタを指します
循環参照: AがBを呼び出し、BがAを呼び出すため、AとBのカウントは初期化中に1、代入中に1プラスされ、破棄されると1減ります。 . 最終的には 1 のままでリソースは解放されません。
ここに画像の説明を挿入
A または B のメンバー変数をweak_ptrに変更するだけです。

this ポインタは本質的に生のポインタであるため、this ポインタをshared_ptr として返さないでください。したがって、this を返すと破棄が繰り返される可能性があります。this
のshared_ptr を返す正しい方法は、ターゲット クラスに std::enable_shared_from_this クラスを渡してから、基本クラスのメンバー関数shared_from_this() を使用してshared_ptr を返すことです。これの:

スマート ポインターはスレッドセーフですか?
結論: 同じshared_ptrは、複数のスレッドで読み取っても安全ですが、同じshared_ptrは、複数のスレッドで書き込んでも安全ではありません。共有参照カウントを持つ異なるshared_ptrは、複数のスレッドで「書き込んで」も安全です。
その理由は、shared_ptr は実際にはオブジェクトへのポインタとカウンタで構成されており、カウンタの加算および減算操作はアトミックな操作であるため、この部分はスレッドセーフですが、オブジェクトへのポインタはスレッドセーフではありません。たとえば、スマート ポインターの代入コピーは、まずポインターをオブジェクトにコピーし、次に参照の数を加算および減算します。参照の数の加算と減算はアトミックな操作ですが、コピーの 2 段階の操作は、ポインターと参照の数はアトミック操作ではないため、スレッドは安全ではありません。手動でロックおよびロック解除します。

auto自動型推論 (以前のバージョンでは、auto キーワードは、static キーワードに相対的な変数の格納型を示すために使用されていました。 auto は、変数が自動的に格納されることを意味します。これは、コンパイラのデフォルトのルールでもあります)書かなくても同じであり、一般的には書かないため、auto キーワードの存在は非常に無味乾燥になります。) auto の典型的な適用シナリオは、
stl のイテレータを定義することです。異なるコンテナーの反復子には異なる型があり、反復子を定義するときにそれを指定する必要があります。イテレータの型は複雑で記述が面倒な場合があるため、ジェネリック プログラミングなど、特定の型を指定したくない場合には、auto が使用されます。
auto によく似た decltype もあり、これも自動型推論です。
decltype (exp) varname [= value] 括弧は省略可能であることを意味しますが、 expに従って型を推定する点と、式が単純または関数であることが異なる点です。auto は初期化する必要がありますが、decltype は初期化しないためです。auto はクラスの非静的メンバー変数には使用できませんが (初期化されていないため)、decltype は使用できます。

C++11右辺値参照右辺値参照は単なる新しい C++ 構文ですが、理解するのが本当に難しいのは、右辺値参照から派生した 2 つの C++ プログラミング手法、つまり移動セマンティクスと完全転送です
C++ または C 言語では、式 (リテラル、変数、オブジェクト、関数の戻り値など) は、さまざまな使用シナリオに応じて左辺値式と右辺値式に分割されます。正確に言うと、C++ の左辺値と右辺値の概念は C 言語から継承されています。
1 代入記号 (=) の左側に配置できる式は左辺値であり、逆に、代入記号の右側にのみ配置できる式は右辺値です。例:
int a = 5; 5 = a; //エラー、5 は左辺値にはできません。C
++ の左辺値は右辺値としても使用できます (例:
int b = 10; // b は左辺値です
a = b; // a と b は両方とも左辺値ですが、b は右辺値として使用できます

2 名前があり、ストレージ アドレスを取得できる式は左辺値であり、それ以外の場合は右辺値です。a と b は変数名で、その格納アドレスは &a と &b を通じて取得できるため、a と b はどちらも左辺値です。逆に、リテラル 5 と 10 には名前も格納アドレスもありません (リテラルは通常レジスタに格納されますが、またはコードとともに保存されるため)、5、10 は右辺値です。
簡単に言えば、左辺値は変数であり、右辺値はリテラル定数です。

引用、「&」を使用します。しかし、この種の参照方法には欠点があり、通常の状態では C++ の左辺値のみを操作でき、右辺値を参照することができません。例:
int num = 10;
int &b = num; //正しい
int &c = 10; //エラー
このため、C++11 標準では、「 &&」表現を使用した右辺値参照と呼ばれる別の参照メソッドが導入されています。
int && a = 10;
a = 100;
cout << a << endl; (ただし、この種の定数右辺値参照は、定数左辺値参照によって実行できるため、変更不可能な定数を参照するため無意味です) 非常に定量的な右辺値参照は達成できます
。ムーブセマンティクスと完全転送
ムーブセマンティクス
で解決される問題:オブジェクトをコピーする際、オブジェクトメンバにポインタがある場合はディープコピー方式(シャローコピーの場合は多重破壊の問題)、ディープコピーが指すメモリリソース一時オブジェクト内のポインタ メンバが大量のヒープ領域に適用される場合、効率は非常に低くなります。
いわゆる移動セマンティクスとは、ディープ コピーではなく移動によって、ポインター メンバーを含むクラス オブジェクトを初期化することを指します。簡単に理解すると、移動セマンティクスは、他のオブジェクト (通常は一時オブジェクト)が所有するメモリ リソースを「使用済みに移動する」ことを指します。std::move は何も移動しません。その唯一の機能は、左辺値を右辺値参照にキャストすることです。その後、その値は、移動セマンティクスの右辺値参照を通じて使用できます。unique_ptr と併用して所有権を譲渡することもできます。

実装方法:手動でコンストラクタを追加しました。他のコンストラクターとは異なり、このコンストラクターは、移動コンストラクターとも呼ばれる右辺値参照の形式でパラメーターを使用します。そして、このコンストラクターでは、num ポインター変数はシャロー コピーコピー方式 (参照はシャロー コピー) を採用し、同時に関数内で元のポインターを NULL にリセットすることで、「同じブロックが複数回解放される」ことを効果的に回避します。状況の発生。
非 const 右辺値参照は右辺値に対してのみ操作可能であり、プログラムの実行結果 (関数の戻り値、ラムダ式など) で生成される一時オブジェクトには名前も格納アドレスへのアクセスも持たないため、右辺値であることがわかっていますクラスにコピー コンストラクターと移動コンストラクターの両方が含まれている場合、一時オブジェクトを使用して現在のクラスのオブジェクトを初期化すると、コンパイラーはこの操作を完了するために移動コンストラクターの呼び出しを優先します。

完全転送の概念は、テンプレート プログラミングの場合と、関数のパフォーマンスが非常に重要な場合にのみ役立ちます。
まず、参照の折りたたみの状況を理解する必要があります。
参照の折りたたみは、テンプレート プログラミングの概念であり、テンプレート推定後の二重参照の状況 (以下に示すように) を解決することです。
テンプレート関数が次のように定義されているとします。
template
void PrintType(T&& param){ ... }
T が int & type の場合、param は int & && type と推定され、C++ 構文ではこの種の二重参照型は許可されません。 (二重参照変数を自分で定義できますが、コンパイラはエラーを出します) そのため、参照の折りたたみに関する規則が策定されています。具体的な規則は次のとおりです。
テンプレート プログラミング** では、二重参照は 1 つの参照 ** (左辺値参照または右辺値参照) に折り畳まれます。折り畳み規則は次のとおりです。いずれかの参照が左辺値参照の場合、結果は左辺値参照になります。それ以外の場合 (つまり、両方が右辺値参照である場合)、結果は右辺値参照になります。

完全な転送: 完全な転送。これは、関数テンプレートが内部的に呼び出される他の関数に独自のパラメーターを「完全に」転送できることを意味します。いわゆる完全性とは、パラメータの値を正確に転送できるだけでなく、転送されたパラメータの左右の値属性が変更されないことを保証できることを意味します。したがって、多くのシナリオで完全な転送が達成されるかどうかは、パラメーター受け渡しプロセスでコピー セマンティクス (コピー コンストラクターの呼び出し) を使用するか、移動セマンティクス (移動コンストラクターの呼び出し) を使用するかを直接決定します

一般に、テンプレート関数を定義するときは、右辺値参照の文法形式を使用してパラメーター type を定義します。これにより、関数は外部から渡される左辺値または右辺値のいずれかを受け取ることができます(そうしないと、右辺値としてのみ見なされます)。参照折りたたみの規則のため、 lvalue ); 次に、C++11 標準ライブラリによって提供されるforword()。 value 属性、および forward は左辺値参照パラメータparam の形式で一律に受信されますこれにより、関数テンプレート内のパラメーターの完全な転送を簡単に実現できるようになります。(利点はステートマシンに似ており、初期状態も同じで、中間プロセスも同じで、最終結果も同じです)

リストの初期化(初期化の均一性)
C++11 では、変数名の後に初期化リストを直接追加して、オブジェクトを初期化できます。C++11 より前では、主に括弧、等号の初期化メソッドがありました。コンストラクターの初期化子リスト。オブジェクトの初期化方法が非常に多いため、学習コストが増加するだけでなく、コード スタイルが大幅に異なってしまい、コードの可読性と均一性に影響を及ぼします。


28 std::function は、コールバック関数とは何かを理解するためにコールバック メカニズムを実装します。関数ポインタ (アドレス) をパラメータとして別の関数に渡す場合、このポインタがそれが指す関数を呼び出すために使用されるとき、これを次のように呼びますコールバック関数。コールバック関数は、関数の実装者によって直接呼び出されるのではなく、特定のイベントまたは条件が発生したときに別の当事者によって呼び出され、イベントまたは条件に応答するために使用されます。
コールバック:デカップリングは以下をもたらします: 効率的かつ柔軟最新の C++ のカプセル化により、モジュール間である程度の独立性が得られます。ただし、モジュールは相互に連携する必要があるため、
コールバックを使用する方が直感的です。 A がコア チームであると仮定します (A は、B が呼び出すための funA 関数を提供します。これはライブラリ関数とみなすことができ、 funA が結果を返すまで待機する必要がある関数を売ります。実行)、B は別のチームです。
funA の実行に時間がかかる場合、コールバックが使用されない場合、A は次の sell() を実行する前に B の実行が完了するのを待たなければなりませんが、これは時間の無駄です。
コールバックは funA(sell) です。sell コールバック関数は A で定義されていますが、B によって呼び出されます。呼び出し後、結果は直接 A に返され、A は待つ必要がありません。** これは効率的
かつ柔軟です: ** sell 関数を funA 関数に直接記述すると、すべてがうまくいきますが、funA は後で何をすべきかわかりません。呼び出し元だけが知っています。したがって、異なる人がそれを呼び出す場合は、異なる関数ポインタを渡すだけで済みます。

考える: なぜそれを使用するのでしょうか?
しかし、関数ポインタをコールバック関数に適用することは、問題を解決する戦略とシステム設計のアイデアを具体化します。このアイデアを説明する前に、コールバック関数は確かにシステム アーキテクチャの問題の一部を解決できることを説明したいと思いますが、システムのあらゆる場所にコールバック関数を配置する必要はありません。システムがコールバック関数でいっぱいであることがわかった場合は、システムをリファクタリングする必要があります。 。コールバック関数自体がシステム構造を破壊する設計思想であり、
つまりコールバック関数の本質は「何をすべきかは我々Bだけが知っているが、いつ何をすべきかは分からず、他のモジュールAだけが知っている」というものです。知っているので、他のモジュールに伝えるために、知っていることをコールバック関数にカプセル化する必要があります。」

関数ポインタは、通常の関数またはクラスの静的関数です。
クラスの非静的関数にすることもできます。

なぜそれを使うのでしょうか?
C言語の時代では、関数ポインタを使って関数をパラメータとして渡すことができ、コールバック関数の仕組みを実装することができました。C++11 以降、std::function テンプレート クラスが標準ライブラリに導入されました。このテンプレートは、関数ポインターの概念を要約しています。std::function<int
(int a, int b)> plusFunc;
任意の戻り値を表すことができます。 value は int で、仮パラメータ リストは int a、int b などの関数ポインタです。
int puls(int a, int b)

{ return a + b; } // 関数名は関数のアドレス、つまり関数plusFunc = plus へのポインターを表し、呼び出し可能なオブジェクトと同じ形式を持ちます。呼び出し可能オブジェクトは単なる関数ポインターではなく、ラムダ式やクラスのメンバー関数ポインターなどである場合もあります。std::function に適切なパラメータ リストと戻り値を入力すると、そのようなすべての呼び出しメソッドに対応できる関数ラッパーになります。std::function にターゲットが含まれていない場合、それは空であると言われ、空の std::function のターゲットを呼び出すと std::bad_function_call 例外が発生します。




std::bind には通常 2 つの関数があります。呼び出し可能なオブジェクトとパラメーターを別の std::function として
バインドして呼び出します(関数と同様) 。 一部のパラメーターのみをバインドし、呼び出し可能なオブジェクトによって渡されるパラメーターを減らします通常の関数をプレースホルダーでバインドするにはstd::bind double callableFunc (double x, double y) {return x/y;} auto NewCallable = std::bind (callableFunc, std::placeholders::_1,2); std: :cout << NewCallable (10) << '\n';バインドの最初のパラメータは関数名で、実パラメータとして通常の関数を使用した場合、暗黙的に関数ポインタに変換されます。したがって、 std::bind(callableFunc,_1,2) は std::bind (&callableFunc,_1,2) と同等です; _1 は std::placeholders::_1 にあるプレースホルダを表します;最初のパラメータは占有されています ビット占有ここで NewCallable を呼び出すと、それに 10 が渡されます。これは実際には callableFunc(10,2); を呼び出すのと同じです。







ラムダ式は短く、コンテキスト データを取得でき、戻り値の定義を省略できます。あまり役に立ちませんが、

同時実行関連の
std::thread はマルチスレッドを実装します。
C++11 より前では、pthread_xxx を使用してスレッドを作成することがありましたが、これは煩雑で読みにくく、C++11 ではスレッドを作成するために std::thread が導入されました。
std::thread t(func); C++11 では、スレッド ID またはシステム CPU の数の取得、スレッドのネイティブ ハンドルの取得、スレッドのスリープ化などの関数も提供されます。 <<
"
現在のスレッド ID " << t.get_id() << endl;
cout << "現在の CPU 番号" << std::thread::hardware_concurrency() << endl;
auto handle = t.native_handle(); // ハンドル pthread 関連の操作に使用できます
std::this_thread::sleep_for(std::chrono::seconds(1));

std::Mutex は主に、タイムアウトありとタイムアウトなしの相互排他、再帰なしの相互排他に分かれます。
C++11 には主に std::lock_guard、RAII ロック カプセル化が含まれており、ロック リソースを動的に解放し、コーディング エラーによってスレッドがロックを保持するのを防ぐことができます。

条件変数は、C++11 で導入された同期メカニズムです。スレッド通知またはタイムアウトによってブロックされたスレッドがウェイクアップされるまで、1 つまたは複数のスレッドをブロックできます。条件変数はロックと組み合わせて使用​​する必要があります。ここでのロックとは以上が std::unique_lock の導入です。

std::future は std::thread よりも高度で、std::future は非同期結果の送信チャネルとして使用され、スレッド関数の戻り値は get() を通じて簡単に取得でき、std::promise は次の目的で使用されます。値をラップし、データを future とバインドします。std::packages_task は、呼び出しオブジェクトをラップし、関数と future をバインドし、非同期呼び出しを容易にするために使用されます。std::future はコピーできません。コンテナにコピーする必要がある場合は、std::shared_future を使用できます。

std::future
スレッドから非同期タスクの結果を返したい場合 (つまり、タスク A の実行はタスク B の戻り値に依存する必要があります)、セキュリティの観点から、一般にグローバル変数に依存する必要があります。 , それは適切ではありません; このため、C+ +11 は std::future クラス テンプレートを提供し、future オブジェクトは非同期操作の結果にアクセスするためのメカニズムを提供し、非同期タスクから返される結果の問題を簡単に解決できます。 。簡単に言えば、 std::future は非同期タスクの結果を取得する
ために使用できるため、スレッド間の同期の単純な手段とみなすことができます。std::future は通常Providerによって作成されます。 Provider は非同期タスクのプロバイダーであると考えることができます。 Provider はスレッド内の共有状態の値を設定し、共有状態呼び出しに関連付けられた std::future オブジェクトを設定します。 get (通常は別のスレッドで) 値を取得します。共有状態のフラグの準備ができていない場合、std::future::get を呼び出すと、プロバイダーが共有状態の値を設定するまで現在の呼び出し元がブロックされます (この時点では、共有状態 (フラグが準備完了になる)、std::future::get は非同期タスクの値または例外 (例外が発生した場合) を返します。プロバイダーは関数またはstd::async のような関数にすることができ、std: :async() 関数については、この記事の後半で紹介します。std::promise::get_future、get_future は Promise クラス std::packages_task::get_future のメンバー関数です。現時点では、get_future は packaged_task のメンバー関数です





std::future は通常、std::async、std::promise::get_future、std::packages_task::get_future によって作成されますが、コンストラクターも提供されます。td::future のコピー コンストラクターは無効になり、デフォルト コンストラクターと移動コンストラクター (パラメーターとして右辺値を使用する移動コンストラクター) のみが使用されます。 std::future::valid() は現在の std :: をチェックします。将来のオブジェクトが有効かどうか

つまりリリースは何らかの共有状態に関連付けられています。有効な std::future オブジェクトは、std::async()、std::future::get_future、または std::packages_task::get_future を介してのみ初期化できます。また、std::future のデフォルトコンストラクタで作成された std::future オブジェクトは無効(無効)ですが、std::future の移動代入後に std::future オブジェクトが有効になることももちろんあります。
std::future::wait()
は、現在の std::future オブジェクトに関連付けられた共有状態のフラグが準備完了になるまで待機します。
共有状態のフラグが準備完了でない場合 (プロバイダーが値を設定していない場合 (または例外) (この時点の共有状態では))、この関数を呼び出すと、共有状態のフラグが準備完了になるまで現在のスレッドがブロックされます。共有状態のフラグが準備完了になると、wait() 関数が戻り、現在のスレッドのブロックが解除されますが、wait() は共有状態の値や例外を読み取りません。(ここが std::future::get() との違いです)
std::future::wait_for() は期間 rel_time を設定できます
std::shared_future は std::future に似ていますが、std::shared_future はコピーでき、複数の std::shared_future で共有状態を共有できます。最終結果パラメータは Future であり、
この Future を使用して int を待機しますtype product : std::future& fut
子スレッドで get() メソッドを使用して、将来の future を待機し、結果を返します。プロデューサは非同期メソッドを使用してプロダクション作業を実行し、フューチャを返します。コンシューマはフューチャで get() メソッドを使用してプロダクトを取得します。

C++14、17については詳しくは紹介しません。C++20 にはさらに多くのコルーチンがあります。

auto自動型推論 (以前のバージョンでは、auto キーワードは、static キーワードに相対的な変数の格納型を示すために使用されていました。 auto は、変数が自動的に格納されることを意味します。これは、コンパイラのデフォルトのルールでもあります)書かなくても同じであり、一般的には書かないため、auto キーワードの存在は非常に無味乾燥になります。) auto の典型的な適用シナリオは、
stl のイテレータを定義することです。異なるコンテナーの反復子には異なる型があり、反復子を定義するときにそれを指定する必要があります。イテレータの型は複雑で記述が面倒な場合があるため、ジェネリック プログラミングなど、特定の型を指定したくない場合には、auto が使用されます。
auto によく似た decltype もあり、これも自動型推論です。
decltype (exp) varname [= value] 括弧は省略可能であることを意味しますが、 expに従って型を推定する点と、式が単純または関数であることが異なる点です。auto は初期化する必要がありますが、decltype は初期化しないためです。auto はクラスの非静的メンバー変数には使用できませんが (初期化されていないため)、decltype は使用できます。

Finalキーワードは、クラスを継承できないようにするため、関数を書き換えることはできません。 override は、仮想関数に
default の書き換えを促します。ほとんどの場合、これは、クラスにカスタム コンストラクターがある場合に、コンストラクターをデフォルト コンストラクターとして宣言するために使用されます。 、コンパイラーは、デフォルトのコンストラクターは暗黙的に生成されません。また、オブジェクトのコピーと代入を禁止したい場合もあります。削除変更を使用できます。delele 関数は C++11 で非常に一般的に使用されており、std::unique_ptr はの削除変更によるオブジェクトのコピーを禁止します。

Explicitはコンストラクターを変更するために特別に使用されます。つまり、コンストラクターは明示的にのみ構築でき、(パラメーターに対して) 暗黙的に変換することはできません。const は読み取り専用のセマンティクスを意味し、実行時に変更できないことのみを保証します
。しかし、まだ変更されています これは動的変数である可能性があり、変更されたconstexpr は実際の定数であり、コンパイル中に計算され、実行プロセス全体中に変更することはできません。constexpr は関数の変更に使用でき、戻り値はこの関数は、可能な限りコンパイル時に定数として計算されます。

タプルtupleの最大の特徴は、インスタンス化されたオブジェクトが、任意の型の任意の量のデータを格納できることです。
C++11 Long Long Super Long 整形
C++11shared_ptr 、unique_ptr、weak_ptr スマート ポインタ詳細は前面を参照

新しいアルゴリズムもいくつかありますが、どれも、どれも含まれていません。

継承されたコンストラクター: 基底クラスのコンストラクターが多数ある場合、派生クラスは基底クラスのコンストラクターを書き換える必要があるため、書き換える必要がなく、base::base を使用して使用できます。

おすすめ

転載: blog.csdn.net/weixin_53344209/article/details/130488817