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

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

詳細はこちら
C++

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

Q&A

解決済

4回答

4558閲覧

autoとdecltype(auto)の違いについて

__ook

総合スコア49

C++

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

2グッド

0クリップ

投稿2019/12/11 02:40

以下のコードを動かしたところ大量の文字列が出力され、エラーとなります。

cpp

1#include <iostream> 2#include <shellapi.h> 3#include <vector> 4#include <algorithm> 5#include <string> 6#include <type_traits> 7#include <thread> 8 9using namespace std; 10 11decltype(auto) retVal(string str) 12{ 13 string str_cp = str; 14 return move(str_cp); 15} 16 17int main() { 18 19 string str = "decltype test"; 20 cout << retVal(str) << endl; 21}

以下のようにmoveを外す、または戻り値をautoにしたところ、正常な挙動となりました。

cpp

1#include <iostream> 2#include <shellapi.h> 3#include <vector> 4#include <algorithm> 5#include <string> 6#include <type_traits> 7#include <thread> 8 9using namespace std; 10 11decltype(auto) retVal(string str) 12{ 13 string str_cp = str; 14 return str_cp; 15} 16 17int main() { 18 19 string str = "decltype test"; 20 cout << retVal(str) << endl; 21}

cpp

1#include <iostream> 2#include <shellapi.h> 3#include <vector> 4#include <algorithm> 5#include <string> 6#include <type_traits> 7#include <thread> 8 9using namespace std; 10 11auto retVal(string str) 12{ 13 string str_cp = str; 14 return move(str_cp); 15} 16 17int main() { 18 19 string str = "decltype test"; 20 cout << retVal(str) << endl; 21}

挙動の違いはなぜ起こったのでしょう?

Bearded-Ockham, yohhoy👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

こんにちは。

「autoとdecltype(auto)の違い」は本の虫のこのエントリーが解りやすいです。
つまり、decltype(auto)を使った場合、retValの戻り値の型が右辺値参照になるということですね。

右辺値参照も参照の一種ですから、ローカル変数str_cpへの参照を返却します。str_cpはretVal関数からreturnしたら破棄されますので、戻り値は破棄された変数を参照しています。ですので、何が起こるか分かりません。

これに対して、autoを使った場合は、戻り値はstring型ですから、return move(str_cp)にてムーブされます。ムーブはちょっと特殊ですが一種のコピーです。(int型などでは単なるコピーです。)
つまりstr_cpがコピーされているのでコピー後にstr_cpが破棄されても問題ないということです。

更に、moveを外した場合、retValの戻り値の型もstring型ですから、str_cpは普通にコピーされて戻されます。(実際には最適化によりコピーが省略されるケースが多いです。)この方法で問題がなければ、これを使った方が安心ですし、高速な場合が多いです。

投稿2019/12/11 03:26

Chironian

総合スコア23272

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

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

0

話がそれますが、return文で返す値をstd::moveするのは常に間違っています。じっさいclangとかはコンパイルのときに警告を出すはずです。std::moveをするとC++17で追加されたコピー省略(RVO)や殆どのコンパイラで行われるNRVOを阻害します。

投稿2019/12/11 17:46

yumetodo

総合スコア5852

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

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

__ook

2019/12/12 01:27

回答ありがとうございます。 そうなのですね。C++14までの規格でも推奨されないのですか?
yumetodo

2019/12/12 02:18

C++14までもほぼすべてのコンパイラがRVOを実装していますので。
__ook

2019/12/12 06:58

知りませんでした…コンパイラって賢いですね… ありがとうございました。
guest

0

ここに分かりやすい説明があります。

std::move は右辺参照にキャストする機能ですから、 retVal の返却値の型を decltype(auto) という風に指定したときは「参照を返している」ということになります。

str_cp は関数を抜けた時点で寿命を終えているので、その参照は無効です。 無効な参照を利用した結果は未定義です。

投稿2019/12/11 03:07

SaitoAtsushi

総合スコア5684

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

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

0

See two articles under this.
https://cpprefjp.github.io/lang/cpp14/decltype_auto.html
https://qiita.com/rinse_/items/ad0cc7e351e836595c94

In short, you cannot return a reference to a local variable using std::move.

投稿2019/12/11 03:21

majiponi

総合スコア1722

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問