Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
return文におけるstd::moveについて
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
onihusube
December 20, 2024
Programming
2.9k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
return文におけるstd::moveについて
return文でstd::moveをいつ使うべきかとその理由を完全理解してください💪
onihusube
December 20, 2024
More Decks by onihusube
See All by onihusube
非侵入的モナド的操作導入ライブラリ harmony とコンセプト・CPO
onihusube
0
240
Other Decks in Programming
See All in Programming
ハーネス設計入門 〜プロンプト、コンテキストの次〜
kinopeee
55
37k
ソフトウェアラスタライザ
fadis
1
800
Intent as Code
shoppingjaws
6
740
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
270
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
140
Press start. Python's next generation.
willingc
PRO
3
330
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
tsc.rip を支える技術 / Kyoto.なんか #8
susisu
0
4.4k
アクセシビリティから考える情報設計
high_g_engineer
0
350
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
4
1.1k
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
120
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
430
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
190
The Invisible Side of Design
smashingmag
301
52k
Scaling GitHub
holman
464
140k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
880
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
How to make the Groovebox
asonas
2
2.4k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
730
Evolving SEO for Evolving Search Engines
ryanjones
0
280
New Earth Scene 8
popppiees
3
2.5k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
Transcript
return文における std::move()について いつstd::moveするべきか?
自己紹介 • C++の沼に嵌って抜け出せない人です • C++が好きです • この名前だと、CEDECでC++の発表を2回くらいしています • インターネットだとキノコのアイコンで活動しています •
物理世界では、株式会社T2という自動運転の会社でC++書いて ます • C++プログラマ積極募集中です! 2
背景 • 以前に書いた本の売り文句に「return文でいつstd::move()をす るべきか完全理解できる!」のようなことを書いた • しかし、本文には明確にその回答を書いていなかった • ずっと気になっていたが、いい機会なのでここで回答を置いて おくことに 以前書いた本
3
目的 • return文でいつstd::move()を書くべきかその理由を完全理解す る • C++17以降を対象とします 4
return文とstd::move • とても典型的には次のようなコードにおいて、return文での std::move()の使用をコンパイラに怒られる auto f() -> std::vector<int> { std::vector
vec = {1, 2, 3, 4}; ... return std::move(vec); // 警告 } g++13.2: warning: moving a local object in a return statement prevents copy elision [-Wpessimizing-move] clang 17.0.1: warning: moving a local object in a return statement prevents copy elision [- Wpessimizing-move] 5
return文とstd::move • std::move()を外すととりあえず何も言われなくなる • でも… • 本当にムーブされてるのか不安 • というかむしろ、std::move()を付けろと怒られた記憶もある •
人もいると思う auto f() -> std::vector<int> { std::vector vec = {1, 2, 3, 4}; ... return vec; // } 6
結果 • return文でいつstd::move()すればいいのかよくわからない • した方が良いように思えるけれど、しなくてもいいの? • とりあえずstd::move()してみてコンパイラに怒られたら外す、 という運用 • コードベースによっては非効率
7
何が分からないのか? • なぜ怒られているのか分からない • RVOと暗黙ムーブ周りの仕様は複雑すぎる • ムーブされているかはコードから見えないので起きていること が分からない • 本当にムーブされているのか?
• むしろ逆の指摘を受けたことがある場合、いつstd::move()が必 要なのか何も分からない ➢「なぜダメなのか?」と「いつ要るのか?」を理解する! 8
なぜ怒られている? • 警告メッセージにある通り、コピー省略最適化を阻害するから • ここでのコピー省略最適化とは、いわゆるNRVOのこと 9 g++13.2: warning: moving a
local object in a return statement prevents copy elision [-Wpessimizing-move] clang 17.0.1: warning: moving a local object in a return statement prevents copy elision [- Wpessimizing-move]
Named Return Value Optimization(NRVO) • 戻り値を引数の参照から返すようにするような最適化 // この関数にNRVOが適用されると auto f()
-> std::vector<int> { std::vector vec = {1, 2, 3, 4}; ... return vec; } // あたかもこう書き替えられたかのように動作する void f(std::vector& ret) { ret = std::vector{1, 2, 3, 4}; ... } 10
なぜNRVOが阻害されるのか? • NRVOは必須ではなく、あくまで許可されている最適化 • そのため、規格ではその適用範囲が指定されている • NRVOの対象となるreturn文は、そのオペランドが丁度変数名 でなければならない • かつ、その変数名はその関数ローカルの非volatile変数であり、関数引
数でもcatch節のパラメータでもない、必要がある • 戻り値型は非参照型 ➢return文のオペランドで関数呼び出ししていると、NRVOできない 11
なぜ関数呼び出しはダメなのか? • ex_func()が中で何をしてるか分からない • ex_func()に渡しているものと帰っているものが一致する保証がない • 定義が見えていればできる場合もあるかもしれないが、現在の 規格ではそこまでの解析を要求していない // こんな素性の良く分からない関数があったとして
auto ex_func(std::vector<int>&) -> std::vector<int>&&; auto f() -> std::vector<int> { std::vector vec = {1, 2, 3, 4}; // NRVO出来そうに見えますか・・・? return ex_func(vec); } 12
std::move()はライブラリ関数! • 先程のex_func()とstd::move()はNRVOの観点で見ると、コンパ イラの視点では差が無い • 規格でもstd::move()やstd::forward()をNRVOにおいて特別扱い すべしとは書いていない • おそらく実装負荷を考慮してのこと •
除外する提案は最近された(P2991R0) • 結果、return文におけるあらゆる関数呼び出しはNRVOを阻害 してしまう • 確実に行われなくする 13
ほとんどの場合std::move()は必要ない • std::move()をしなくても、暗黙ムーブされるため • 暗黙ムーブの対象は • C++17まで: ローカルの非volatile変数 • C++20以降:
+ローカルの非volatile右辺値参照 • return文のオペランドは変数名 • あるいは、()で囲まれていても良い ➢return文における関数呼び出しは暗黙ムーブも阻害する • 上記を満たしたうえで • C++20までは、return文でコピーが起こる場合、代わりにまずムーブ を試みる • C++23からは、オペランドがxvalueとして扱われる 14
暗黙ムーブのバージョンごとの対象範囲 • C++11 • 戻り値型と同じ非参照ローカル変数の暗黙ムーブ • オペランド型の右辺値を受ける変換コンストラクタへの暗黙ムーブ • C++20 •
ローカル右辺値参照の暗黙ムーブ • 変換演算子による戻り値型への変換時の暗黙ムーブ • 戻り値型コンストラクタへの暗黙ムーブ • 派生クラスから基底クラスへの変換が起こる場合の暗黙ムーブ • C++23 • 戻り値型が参照型の場合の暗黙ムーブ 15
暗黙ムーブの一例 auto ex_11(std::vector<int> vec) -> std::vector<int> { return vec; //
暗黙ムーブ、C++11から } auto ex_20(std::vector<int>&& vec) -> std::vector<int> { return vec; // 暗黙ムーブ、C++20から } auto ex_23(std::vector<int>&& vec) -> std::vector<int>&& { return vec; // 暗黙ムーブ、C++23から } 16
それでもstd::move()が必要な場合 • C++20の場合、C++23で許可された範囲のもの • 戻り値型が右辺値参照型であり、ローカルの右辺値参照をreturnする 場合 • C++23以降はこれも暗黙ムーブ対象なのでstd::move()は不要 • とはいえこの場合はあっても警告はされないはず
• std::move()そのもののような場合を除いて普通はこんなコード書かないでしょ auto f(std::vector<int>&& vec) -> std::vector<int>&& { // 戻り値型が右辺値参照型の場合のローカル右辺値参照の暗黙ムーブ return vec; // C++20まで // C++20まではstd::move()必須 return std::move(vec); // } 17
それでもstd::move()が必要な場合 • C++17までなら、C++20以降で許可された範囲のもの • 次の場合、C++17では暗黙ムーブ対象ではない • ローカル右辺値参照の暗黙ムーブ • 変換演算子による戻り値型への変換時の暗黙ムーブ •
戻り値型コンストラクタへの暗黙ムーブ • 派生クラスから基底クラスへの変換が起こる場合の暗黙ムーブ • returnしようとする値と戻り値型が異なる場合、とほぼまとめられる 18
C++17で暗黙ムーブされない例 auto f1(std::vector<int>&& vec) -> std::vector<int> { return vec; //
右辺値参照の暗黙ムーブ、C++20から } struct To { operator std::vector<int>() &&; }; auto f2(To t) -> std::vector<int> { return t; // 暗黙ムーブによる変換演算子適用、C++20から } struct V { V(std::vector<int>); }; auto f3(std::vector<int> vec) -> V { return vec; // コンストラクタ引数への暗黙ムーブ、C++20から } auto f4(Derived d) -> Base { return d; // 基底クラスへの変換時の暗黙ムーブ、C++20から } 19
それでもstd::move()が必要な場合 • 言語バージョンとは関係なく必要な場合がある • 戻り値型のコンストラクタを明示的に呼び出す場合 • 特に、2引数以上を渡そうとする場合 • return文のオペランドが変数名ではなくなるため •
同様に、return文で関数呼び出ししているとその引数は暗黙ムーブ されない • が、これはあまり驚きはなさそう auto f1(std::vector<int> vec) -> std::pair<int, std::vector<int>> { return {20, vec}; // コピーされる return {20, std::move(vec)}; // ムーブされる } 20
それでもstd::move()が必要な場合 • return文で関数呼び出ししている場合で、関数呼び出し感がな いもの ➢演算子を適用している場合 • これは特に、ポインタでも必要 auto f(std::optional<std::vector<int>> opt)
-> std::vector<int> { if (!opt) { return {}; } return *opt; // コピーされる return std::move(*opt); // ムーブされる return *std::move(opt); // ムーブされる } 21
まとめ 1. return文のオペランドで関数呼び出しをしていると、NRVO (コピー省略も)が行われなくなる • std::move()も例外ではない 2. return文においてstd::move()をしなくても、ほとんどの場合 暗黙ムーブによってムーブされている •
バージョン毎の差分がややこしい… ➢retrun文においてstd::move()は通常使用する必要は無い ➢C++20以降は特に ➢別の関数呼び出しを伴っている場合は、必要がある場合もある ➢コンストラクタ呼び出しや、*演算子など 22
PR • 株式会社T2ではC++プログラマを積極採用して います! • 自動運転の会社です • C++17でプログラミングできます!! • カジュアル面談から受け付けています!!!
• https://t2.auto/recruit/ 23