525 Views
June 20, 26
スライド概要
C++ breaktime 2026/Summerの発表資料です。
https://cpp-osaka.connpass.com/event/393713/
RAIIと所有権の話 @zbdk
おことわり ■ この発表は知っている人から見ると当たり前の話です ■ あえて触れていない部分があります – 左辺値、右辺値 2
いきなりですが ■ C++を書いていて以下の経験をしたことがある人 – メモリリークさせたことがある – 二重解放させたことがある 3
メモリリーク ■ 確保したメモリを解放せずに手放すこと ■ メモリが枯渇してストップの原因に 4
二重解放 ■ すでに解放済みのリソースを再度解放してしまうこと ■ ストップなどの未定義動作に 5
そんなことしないって1 ■ 本当に? deleteが呼び出されない 6
そんなことしないって2 ■ 本当に?? structA MyClass structB 7
今日のテーマ ■ メモリリークや二重解放をしないための仕組み 8
メモリリーク対策 ■ RAIIを使ってメモリ管理を行う ■ RAII – オブジェクト生成(コンストラクタ)時に リソースを確保 – オブジェクト破棄(デストラクタ)時に リソースを解放 ■ RAIIの例 – scope_exit 9
scope_exit (1/2) ■ 関数を登録しておき scopeが終わる際に 登録した関数を 実行できるライブラリ ■ 良いお知らせ – 標準ライブラリと して提案中 deleteが呼び出される 10
scope_exit (2/2) ■ 悪いお知らせ – 未だに採択されない – 2013年から議論中 (N3677) ■ 実験的に実装されてはいる – std::experimental::scope_exit – GCCやClangだと使えるかも – VisualStudio2022では使えませんでした・・・ 11
RAIIクラス ■ じゃあ標準でメモリに関するRAIIクラスは 用意されてないの? ■ あります – std::unique_ptr 12
std::unique_ptr(C++11~) ■ scopeが終わったタイミングでメモリ破棄を行いだけで あればstd::unique_ptrが利用可能 13
何がユニークなの? ■ そのリソースの所有権を唯一持っている点でユニーク ■ コピーができない – できてしまうとコピー元とコピー先で同じリソースを 指すポインタを持つことになってしまう(非ユニーク) ptr1 ptr2 MyClass 14
所有権の移動 ■ じゃあリソースはunique_ptrと心中するしかない? – std::moveを使うことで所有権の移譲が可能 – move先にポインタが移動し、move元は何も所有しな い状態になる ptr1 ptr2 MyClass 15
std::unique_ptrのメリット ■ unique_ptrの寿命が尽きた際、自動的にdeleteしてくれる – 自分でdeleteを書かないので解放漏れ、二重解放のリ スクが低くなる ■ 誰が所有しているのかが明確になる – 生ポインタだと所有と参照の違いがわからず、 new/deleteしているかで判断する必要がある – unique_ptrだと実際の処理を確認しなくても ヘッダの記述だけで所有がわかる 16
std::unique_ptrのデメリット? ■ オーバーヘッドが生じるので処理速度に影響があるかも ■ プログラミングにおいては「かもしれない運転」よりも 実際に計測してみる方が大事 ■ 生成AIにベンチマークプログラムを書いてもらった 17
生成・破棄の計測 ■ どれも50ns程度の実行コストで変わらない 18
間接参照の計測 ■ rawとsmartの差はなく、先ほど(50ns)より速い 19
その他の計測まとめ 20
まとめ ■ メモリの確保解放はRAIIクラスにまかせよう – メモリリークや二重解放を防げる ■ exit_scopeはスコープ終了時の処理を登録できるクラス – リソースの解放処理を書いておける – 標準化はされていないがリファレンス実装がある ■ std::unique_ptrはそのメモリを唯一所有するクラス – std::moveで所有権を移譲できる – 低オーバーヘッド 21