84669 人が学習中
152542 人が学習中
20005 人が学習中
5487 人が学習中
7821 人が学習中
359900 人が学習中
3350 人が学習中
180660 人が学習中
48569 人が学習中
18603 人が学習中
40936 人が学習中
1549 人が学習中
1183 人が学習中
32909 人が学習中
认证高级PHP讲师
上記は、コピー コンストラクターが呼び出される理由を説明しています。なぜそれが混乱するのかを説明しましょう。
まず、本質的な理由はベクトル拡張です。初期容量は 0 で、最初の演算は 1 に拡張され、2 番目の演算は 2 に倍増します。
Mac で Clang++ を使用しています。これが呼び出す stl 実装は libcxx である必要があります。これは、libcxx の Vector Push_back 実装のソース コードから確認できます。
ソースコードはここでご覧いただけます https://github.com/llvm-mirro...
__push_back_slow_path の実装は次のようになります
最初に容量が拡張され、__recommend が拡張作業を行ってから、新しいコンテンツが構築され、__a の後半の先頭に配置されることがわかります。移動またはコピーでき、最後に _swap_out_circular_buffer 関数を実行します。 __swap_out_circular_buffer の実装は次のとおりです:
反復子とサイズの処理に注目する必要はありません。重要な点は、前のベクトルのデータを新しいベクトル メモリ領域にコピーまたは移動する役割を担う __alloc_traits::__construct_backward です。 __construct_backward の実装はこんな感じ
move_if_noExcept から、移動操作を実行するには noExcept でなければならないことがわかります。この操作は end から開始され、begin まで反復子が減少するため、逆の順序になります。
最初のpush_backを実行するときは、容量が不足していることを確認し、__push_back_slow_path関数を実行し、ベクトルを1に拡張し、移動コンストラクターを実行します。元のベクトルは空であるため、それ以上の処理は必要ありません。
これは初めての印刷です Move constructor is called. source: hello
Move constructor is called. source: hello
2回目のpush_back実行時は、容量が足りないことを確認し、__push_back_slow_path関数を実行し、ベクトルを2に展開し、移動コンストラクタを実行します。
これは 2 刷目です Move constructor is called. source: world
Move constructor is called. source: world
次に、__swap_out_circular_buffer を実行し、__alloc_traits::__construct_backward を呼び出します。移動コンストラクターは noExcept ではないため、コピー コンストラクターを 1 回呼び出します。
__swap_out_circular_buffer
__alloc_traits::__construct_backward
これは 3 番目の印刷です Copy constructor is called. source: hello
Copy constructor is called. source: hello
要素が増えると、その後のコピー コンストラクターの実行順序が元のベクトルの順序と逆になることがわかります。その理由は、上記でも述べたとおり、演算は末尾から始まり、反復子は減少し続けます。始めます。
移動コンストラクターは noExcept ではないからです。移動コンストラクターを noExcept(true) として宣言すると、ベクターはコピー コンストラクターを呼び出しません。
vector の Push_back には拡張ストレージ領域が必要になる場合があります。このプロセスには、元の記憶領域から新しく適用された記憶領域への元のデータのコピーが含まれます。同時に、push_back は、要素を追加するプロセス中に操作で例外がスローされた場合に、コンテナーが Push_back 前の状態を維持することを保証する必要があります。したがって、例外をスローする可能性がある移動コンストラクターを呼び出すことはできません。意味的に言えば、移動構築操作を中断する (例外をスローする) とデータ破損が発生するためです。
意味的に言えば、データ破損を引き起こさないため、例外をスローする可能性のあるコピー コンストラクターを呼び出します。もちろん、コピー コンストラクターで何かを行うこともできます。
上記は、コピー コンストラクターが呼び出される理由を説明しています。なぜそれが混乱するのかを説明しましょう。
まず、本質的な理由はベクトル拡張です。初期容量は 0 で、最初の演算は 1 に拡張され、2 番目の演算は 2 に倍増します。
Mac で Clang++ を使用しています。これが呼び出す stl 実装は libcxx である必要があります。これは、libcxx の Vector Push_back 実装のソース コードから確認できます。
ソースコードはここでご覧いただけます https://github.com/llvm-mirro...
リーリー__push_back_slow_path の実装は次のようになります
リーリー最初に容量が拡張され、__recommend が拡張作業を行ってから、新しいコンテンツが構築され、__a の後半の先頭に配置されることがわかります。移動またはコピーでき、最後に _swap_out_circular_buffer 関数を実行します。
リーリー__swap_out_circular_buffer の実装は次のとおりです:
反復子とサイズの処理に注目する必要はありません。重要な点は、前のベクトルのデータを新しいベクトル メモリ領域にコピーまたは移動する役割を担う __alloc_traits::__construct_backward です。
リーリー__construct_backward の実装はこんな感じ
move_if_noExcept から、移動操作を実行するには noExcept でなければならないことがわかります。この操作は end から開始され、begin まで反復子が減少するため、逆の順序になります。
最初のpush_backを実行するときは、容量が不足していることを確認し、__push_back_slow_path関数を実行し、ベクトルを1に拡張し、移動コンストラクターを実行します。元のベクトルは空であるため、それ以上の処理は必要ありません。
これは初めての印刷です
Move constructor is called. source: hello
2回目のpush_back実行時は、容量が足りないことを確認し、__push_back_slow_path関数を実行し、ベクトルを2に展開し、移動コンストラクタを実行します。
これは 2 刷目です
Move constructor is called. source: world
次に、
__swap_out_circular_buffer
を実行し、__alloc_traits::__construct_backward
を呼び出します。移動コンストラクターは noExcept ではないため、コピー コンストラクターを 1 回呼び出します。これは 3 番目の印刷です
Copy constructor is called. source: hello
要素が増えると、その後のコピー コンストラクターの実行順序が元のベクトルの順序と逆になることがわかります。その理由は、上記でも述べたとおり、演算は末尾から始まり、反復子は減少し続けます。始めます。
移動コンストラクターは noExcept ではないからです。移動コンストラクターを noExcept(true) として宣言すると、ベクターはコピー コンストラクターを呼び出しません。
vector の Push_back には拡張ストレージ領域が必要になる場合があります。このプロセスには、元の記憶領域から新しく適用された記憶領域への元のデータのコピーが含まれます。同時に、push_back は、要素を追加するプロセス中に操作で例外がスローされた場合に、コンテナーが Push_back 前の状態を維持することを保証する必要があります。したがって、例外をスローする可能性がある移動コンストラクターを呼び出すことはできません。意味的に言えば、移動構築操作を中断する (例外をスローする) とデータ破損が発生するためです。
意味的に言えば、データ破損を引き起こさないため、例外をスローする可能性のあるコピー コンストラクターを呼び出します。もちろん、コピー コンストラクターで何かを行うこともできます。