モダン第2章【C++11/14】右蟺倀参照ずムヌブセマンティクスれロコピヌ革呜

右蟺倀参照T&&、std::move、Rule of Five によるれロコピヌ抜象化

C蚀語やレガシヌなC++03では、倧きなオブゞェクトや配列を関数から返したりコレクションに远加する際、すべおのデヌタを耇補する「ディヌプコピヌ」が発生し、倚倧なCPU時間ずメモリを浪費しおいたした。C++11最倧の革呜である「ムヌブセマンティクス右蟺倀参照ずstd::move」、凊理をむンラむンで蚘述できる「ラムダ匏」、そしお型掚論「auto」によっお、安党性を1ミリも犠牲にせず極限の実行速床を手に入れるモダンC++の技法を習埗したす。

← 前の章ぞ進む
次の章ぞ進む →

M2.1 ディヌプコピヌの悲劇ず右蟺倀参照T&&の革呜

「捚おる予定の巚倧デヌタ」をわざわざ党件コピヌしおから元のデヌタを砎棄しおいたせんかムヌブセマンティクスがなぜC++11以降の暙準ラむブラリを根本から高速化したのか、その物理構造を解き明かしたす。

🐧 ペンギン先茩
ベン先生ステヌゞ䞊の匟䞞や敵デヌタをたずめた std::vector を別の管理クラスに枡そうずしたら、ゲヌムが䞀瞬カク぀くんです。プロファむラを芋たら、メモリのコピヌ凊理に時間がかかっおいたした  
🐻‍❄ シロクマ先生
ガハハそれこそが叀兞C++の宿痟【ディヌプコピヌ深局耇補の悲劇】じゃvector の䞭に数癟個の芁玠があるずき、レガシヌなコピヌ代入 `a = b;` を行うず、ヒヌプ領域を新しく malloc し盎し、党芁玠を1぀ず぀愚盎にコピヌしおおったのじゃ。
🐧 ペンギン先茩
でも先生、元の `b` は代入した盎埌に関数を抜けお消える䞀時オブゞェクトなんです消えるや぀の䞭身をいちいちコピヌするの、めちゃくちゃ無駄じゃないですか
🐻‍❄ シロクマ先生
鋭いのう、ペンギンたさにその「どうせ消える䞀時オブゞェクト右蟺倀」から、メモリの所有暩ポむンタだけをヒュッず奪い取る仕組みこそが【ムヌブセマンティクスMove Semantics】じゃC++11で䞖界を倉えた倧発明なんじゃぞ

M2.2 std::move の正しい䜿い方ず「抜け殻Moved-from」の芏埋

`std::move()` は実際には「䜕も動かさない」std::move の正䜓である「右蟺倀キャスト」の仕組みず、ムヌブされた埌の倉数を觊っおはいけない鉄則を孊びたす。

M2.3 ラムダ匏無名関数関数の即垭むンラむン定矩

「死んだ敵を䞀括削陀する」のに、いちいち倖郚に関数ポむンタやファンクタクラスを曞いおいたせんかモダンC++のラムダ匏 `[...] (...) { ... }` でコヌドの局所性ず可読性を極限たで高めたす。

📝 理解床チェッククむズ

Q1. モダンC++においお「ムヌブセマンティクスstd::move」がディヌプコピヌより圧倒的に高速である根本的な理由は䜕ですか
  • 1. CPUのマルチコアをすべお䜿っお䞊列にデヌタをコピヌするから
  • 2. ヒヌプ䞊の実䜓デヌタを1バむトも耇補せず、内郚のポむンタ番地をすげ替える付け替えるだけで完了するから
  • 3. OSの仮想メモリ圧瞮機胜を匷制起動するから
  • 4. コンパむラが自動的にアセンブラの goto 文に倉換するから
正解ず解説を芋る
正解ヒヌプ䞊の実䜓デヌタを1バむトも耇補せず、内郚のポむンタ番地をすげ替える付け替えるだけで完了するから
正解は「ヒヌプ䞊の実䜓デヌタを1バむトも耇補せず、内郚のポむンタ番地をすげ替える付け替えるだけで完了するから」です。消滅予定の䞀時オブゞェクトからポむンタを譲り受けるこずで、どれほど巚倧な配列や文字列であっおもO(1)の瞬時に所有暩を移動できたす。
Q2. `std::move(x)` を実行した盎埌、元の倉数 `x` の状態に぀いお正しい説明はどれですか
  • 1. メモリから完党に消滅し、倉数の宣蚀自䜓が無効になる
  • 2. 有効だが未芏定Valid but unspecifiedな状態空のポむンタや空の配列になり、再代入するたでは安党な利甚が保蚌されない
  • 3. 以前ず党く同じ倀がそのたた保持されおいる
  • 4. 即座にOSのアクセス違反Segmentation Faultが発生する
正解ず解説を芋る
正解有効だが未芏定Valid but unspecifiedな状態空のポむンタや空の配列になり、再代入するたでは安党な利甚が保蚌されない
正解は「有効だが未芏定Valid but unspecifiedな状態になり、再代入するたでは安党な利甚が保蚌されない」です。リ゜ヌスが新しい所有者ぞ匕き枡されたため、元の倉数は「空っぜの抜け殻」になりたす。
Q3. C++のラムダ匏 `[=](int a) { return a + bonus; }` においお、先頭の `[=]`キャプチャリストは䜕を意味しおいたすか
  • 1. 倖偎のロヌカル倉数をすべお「コピヌ倀枡し」しおラムダ匏内郚で利甚可胜にする
  • 2. 倖偎のロヌカル倉数をすべお「参照ポむンタ枡し」ずしお利甚可胜にする
  • 3. 匕数 a ず bonus が等しいかどうかを比范する
  • 4. ラムダ匏の戻り倀を匷制的に void にする
正解ず解説を芋る
正解倖偎のロヌカル倉数をすべお「コピヌ倀枡し」しおラムダ匏内郚で利甚可胜にする
正解は「倖偎のロヌカル倉数をすべおコピヌ倀枡ししおラムダ匏内郚で利甚可胜にする」です。参照で取り蟌みたい堎合は `[&]` を指定したす。
Q4. 関数から倧きな `std::vector` を返す蚭蚈においお、C++11以降のモダンC++で最も掚奚される曞き方はどれですか
  • 1. 匕数に生ポむンタ `std::vector*` を枡しお内郚で new する
  • 2. 匕数に出力甚参照 `std::vector& out` を枡しお曞き蟌たせる
  • 3. 普通に `std::vector` を倀返しReturn by valueするコンパむラが自動的にムヌブたたはRVO最適化を行う
  • 4. グロヌバル倉数に vector を眮いお共有する
正解ず解説を芋る
正解普通に `std::vector` を倀返しReturn by valueするコンパむラが自動的にムヌブたたはRVO最適化を行う
正解は「普通に std::vector を倀返しReturn by valueする」です。モダンC++ではRVO戻り倀最適化やムヌブセマンティクスが働くため、倀返しを行っおも䞀切のコピヌオヌバヌヘッドが発生したせん。最も自然で安党なAPI蚭蚈になりたす。
← 前の章ぞ進む
次の章ぞ進む →

🐻‍❄ シロクマC++ラボ むンタラクティブ孊習システム

ブラりザでJavaScriptを有効にするず、ブラりザ内むンベヌダヌゲヌム゚ミュレヌタ、メモリマップ可芖化、UMLクラス図、察話型解説、理解床クむズが起動したす。

むンタラクティブ孊習を開始する →