🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

878閲覧

右辺値参照とmove使用について

__ook

総合スコア49

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/12/16 02:25

以下のa, bが行っていることは同じと考えて問題ないでしょうか。
また、cの構文に問題はありますか。

cpp

1#include <iostream> 2#include <fstream> 3#include <string> 4#include <vector> 5 6using namespace std; 7 8auto ret(int x) 9{ 10 return x; 11} 12 13int main() 14{ 15 int&& a = ret(100); 16 int b = move(ret(100)); 17 int&& c = move(ret(100)); 18 19 cout << a << endl; 20 cout << b << endl; 21 cout << c << endl; 22}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

以下のa, bが行っていることは同じと考えて問題ないでしょうか。

いいえ。 違います。

int&& a = ret(100);ret(100) によって作られる一時的なオブジェクトの参照を a として定義しています。 通常はそのような一時的なオブジェクトは完結式 (完全式とも言います) に解体されて無効になるのですが、参照で受けた場合に限って参照のスコープの終わりまで寿命が延長されるルールになっています。 この場合はどこかに 100 というオブジェクトがあって a という別名があるという状態です。

int b = move(ret(100)); は普通にコピーしているだけです。 std::move はその名称に反してムーブする機能を持っていません。 もしそのクラスがムーブコンストラクタを持っている場合にそれを起動するような文脈を作り出すのが std::move の役割です。 int はムーブしませんからこの場面での move は無意味です。 100 というオブジェクトが作り出されてそれを b にコピーした後に一時的なオブジェクトは解体されるという順序になります。

また、 int では効率的な問題にはなりませんが状況によっては move が無ければコンパイラがコピーを省略して直接構築する最適化をしても構わない文脈に適合する場合があります。 (C++17 以降では条件に合致すれば許容されるだけでなく必ずしなければならないように変更されました。) ムーブをした方が効率的とは限らないということには気を付けてください。

また、cの構文に問題はありますか。

文法規則上の問題はないはずですが move を書く意味はありません。

プログラムは機械が解釈するだけではなく人間も読み書きするものですから、書かれていることに意図 (プログラム的には機能していなくても) を読み取ろうとして混乱するということはあるかもしれません。 自分が書いたものでも後で読み返すとよくわからんというのもよくあることなので、理由なく冗長に書くのはお勧めできません。 (逆に言えば自分なりに特別な意図の表現として書くなら悪いわけではありませんが、イディオムとして確立しているものを除いてはコメントで書いておいた方が良いと思います。 時間を置くとびっくりするほど忘れます。)

投稿2019/12/16 04:15

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

__ook

2019/12/16 04:29

moveはmoveしない…?右辺値へのキャストを行っているわけではない、のですね? なるほど、つまりこのbはただのコピー… > また、 int では効率的な問題にはなりませんが状況によっては move が無ければコンパイラがコピーを省略して直接構築する最適化をしても構わない文脈に適合する場合があります。 RVO的みたいなものですかね、なるほど…
SaitoAtsushi

2019/12/16 04:39

move は右辺参照へのキャストをしていますが、その参照を受け取ってムーブの処理をする機能がどこかに書かれていなければムーブにならないということを言っています。 コピーの省略についてはまさに RVO のことを言っています。 ムーブするよりは直接構築した方が速いので RVO が出来るはずの文脈でムーブにしたらもったいないなぁという話です。
__ook

2019/12/16 04:42

すみません、今理解しました。 ああ…moveってそういうことなのですね…ありがとうございました…
SaitoAtsushi

2019/12/16 05:54

右辺値はだいたい一時的なオブジェクトなのでどうせすぐ捨てられるから内容を再利用しても問題なく、だから左辺値か右辺値かの違いによってコピーかムーブかを使い分けられると便利だというのが基本的な考え方です。 言語のコアの機能としては区別できるだけです。 もしあなたがやりたければコピーコンストラクタでムーブしてムーブコンストラクタでコピーするようなクラスを定義することも出来なくはないです。 (それが便利であるような場面は想像もできませんが。) std::move は左辺値を右辺値ということにする機能なので、最初から右辺値の場合には std::move を使う必要はありません。
__ook

2019/12/16 06:05

とても理解できました。ありがとうございます。 ちなみになのですが以下のコード int a = 100; int&& a = 100; については下の宣言のほうが省メモリなのでしょうか?
SaitoAtsushi

2019/12/16 06:42

実体としては参照はポインタとほぼ同じです。 自動で dereference されるポインタだと思ってもよいです。 つまり、右辺値を参照で受けるというのは素朴なコンパイラではオブジェクト自体とポインタの領域を必要とし、普通に変数に格納するよりも多くのメモリを必要とします。 前者の方が省メモリです。 が、主要な C++ コンパイラは強力な最適化機構を持っています。 そんな素朴な処理をしません。 別途領域を確保する必要がないことを見抜いて単純化しますし、整数なら普通の変数すらつぶして即値にすることもあるでしょう。 結局、実行コストとしては差はないはずです。 差はないのであえて後者で書く意味はないですね。
__ook

2019/12/16 07:18

関数の戻り値のみ後者の書き方をすると恩恵が得られる、ということでしょうか。
SaitoAtsushi

2019/12/16 08:44

値が欲しければ値として受け取るべきですし参照が欲しければ参照として受け取るというだけのことなので、状況を想定せずに値と参照を比較する意味はないです。
__ook

2019/12/17 01:04

かなりわかりました…ありがとうございました。
guest

0

こんにちは。

以下のa, bが行っていることは同じと考えて問題ないでしょうか。

見た目はほぼ同じですが、処理内容は全く異なります。
aはret()関数が返す一時オブジェクトを参照し、かつ、寿命を延ばします。
bはret()関数が返す一時オブジェクトをコピーすることで寿命を延ばします。
どちらも変数a, bにてret()の戻り値をアクセスできるという点で「見た目」は同じですが、bはコピー処理が入ります。

cの構文に問題はありますか。

単に冗長なだけで問題はないと思います。

投稿2019/12/16 03:16

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

__ook

2019/12/16 04:24

ああ、つまりbはただのコピーした変数ということですね…? アドレスを確かめたときに違いがあったのはそういうことですね…
Chironian

2019/12/16 04:30

その通りです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問