/ 最近 .rdf 追記 編集 設定 本棚

脳log[20191107]



2019年11月07日 (木) [C++] ムーブセマンティクスと右辺値参照。未だによくわからないけどちょっとヒントになりそうなことに気がついた(気がする)。題材は自分も答えが欲しかったこの疑問。「誰も疑問を呈していないことに自分は疑問なのですが、push_back と emplace_back にトレードオフの関係はないのですか? emplace_back に利点しかないのだとしたら、そもそも関数が分けられずにライブラリ側の push_back 自体の実装が効率の良いものに置き換わるだけで済んだように自分は想像しましたが……。関数が分かれている以上は何かしら使い分けしてほしい意図(ライブラリ側の意図)ががあるものではないのですか?」■よくわからない理由に、右辺値というものの見え方がプログラマとコンパイラの間で180度変わることがあるんじゃないかと思った。最初にそこを区別せずに、右辺値があーだムーブがこーだという文章を読んでも、それぞれが矛盾することを書いているように感じられるのではないか。■右辺値というのはこれまで一時オブジェクト、書き込みできない値、プログラマの制御下にない値だった。ムーブセマンティクスをプログラマが表現できることになり、右辺値でないものを右辺値であるとマークできるようになった。それはプログラマにとって、値に対する制御を手放すという意思表示である。ちょうどコピーした auto_ptr が所有権を手放すがごとく。■コンパイラから見ると従来の右辺値と右辺値であるとマークされた値は、自身が破壊のタイミングを握っている(渡された)、制御下にある値である。■最初の疑問に戻る。emplace_back(push_back のムーブ版だと思ってるけど実は知らない)を使用することは、プログラマに引数となった値に対する制御を手放すことを要求するので、プログラマ自身が意図を込めて選ぶべきものになっているのだと思う。■push_back にムーブ版のオーバーロードを追加することもできたと思うんだけど、できないんだろうか、できるけどやらない方がいいという判断なのだろうか。それはどういう? オーバーロードがあれば T v; c.push_back(move(v)) みたいなコードを書いて呼び分けることになったと思う。■たぶん std::move って書いても書かなくても同じな場面が多くあると思う。ムーブしてきた値を受け取る側からしても、&& と書いたからといって特別な何かが必ず期待できるわけではないらしいし。俺は煩わしいからできるだけ書きたくないし、書いた方がちょっとだけ嬉しい場面でも書かずに済ませたいクチ。■コンストラクタと代入演算子がムーブとコピーがオーバーロードされる例か。かつての auto_ptr の所有権移転コードのようなものを書くみたい。うっかりリソースを共有した状態にすると二重解放の罠。auto_ptr と違ってちょっとわかりにくいのは、値に対して所有権を持っていないというのがどういう状態か想像しにくいこと。ポインタであれば値が NULL であるとか、値はあっても弱参照でありいつまでデリファレンスできるか不明であるとかが想定されるのだけど。■おべんきょ。「C++のムーブと完全転送を知る - Fixstars Tech Blog /proc/cpuinfo」「メイドでもよく分る右辺値参照 - TXT.TXT」■git もだいぶ時間がかかったけど(ものぐさなだけとも言う)、だいぶ煮詰まってきたんじゃないだろうか。かつての C++ In-Depth シリーズのような本が読めないのが残念でならない。そういう研究が必要ないというのなら、C++ が言語として進化したのではなく単に充実しただけであるということ。進化がないのも研究書が読めないのもどちらも不満。■ムーブってついつい一時オブジェクトの省略(※コピーや移動の終着地点に最初から一度だけオブジェクトを構築して済ませてしまう)と結び付けて効率化の手段だと考えてしまうけど、プログラマが書いたムーブコンストラクタが実行されるなら、それはコピーコンストラクタが実行されるのと変わりがないのでは? 利点があるとすればメンバとして保持する外部リソース(ヒープメモリ、ハンドルなど)の確保が省略できる、奪い取って間に合わせられるという点にしかないのでは?■俺は auto_ptr が大好きだし、その制約も喜んで受け入れるし、Rust のメモリ管理も好きだけど(「Rustは何が新しいのか(基本的な言語機能の紹介) - いもす研 (imos laboratory)」)、ムーブは面倒くさいなあ。これまで通りコンパイラの最適化に期待するだけにして、面倒は避けたい、必要に迫られるまでは。