質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.36%
C++11

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

C++

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

Q&A

解決済

2回答

1610閲覧

C++でrvalueを範囲for文で回すことは規格的にOKか?

ttact

総合スコア170

C++11

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

C++

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

2グッド

2クリップ

投稿2020/08/31 01:18

編集2020/08/31 01:47

for(auto& element : container)のスタイルで範囲for文で回すとき、containerの部分に関数の戻り値を書いてもいいのかどうかを知りたいです。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
の6.5.4節(128ページ)、及び
https://cpprefjp.github.io/lang/cpp11/range_based_for.html
を読んだ感じでは、range-initがrvalue referenceで一度受けたコードと同等と説明されているので大丈夫そうな気がしますが、普段は規格を読まないので私の解釈が合っているのか自信がなく...
正確にご存じの方はいらっしゃいますか。

下記コードをVS2017及びgcc10.1.0(Wandbox)でビルド・実行したところは、一応動いてます。

C++

1#include <vector> 2#include <string> 3#include <iostream> 4 5 6class Hoge 7{ 8public: 9 std::vector<std::string> get() 10 { 11 return std::vector<std::string> 12 { 13 "0", 14 "1", 15 "2", 16 }; 17 } 18}; 19 20 21int main() 22{ 23 Hoge h; 24 for(auto& str : h.get()) 25 { 26 std::cout << str << "\n"; 27 } 28}
Bull, tiitoi👍を押しています

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

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

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

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

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

guest

回答2

0

C++でrvalueを範囲for文で回すことは規格的にOKか?

はい。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
の6.5.4節(128ページ)、及び
https://cpprefjp.github.io/lang/cpp11/range_based_for.html
を読んだ感じでは、range-initがrvalue referenceで一度受けたコードと同等と説明されているので大丈夫そう

上記の理解で問題ありません。気にされているのは★箇所だと思いますが、ここではh.get()が返した一時オブジェクトを右辺値参照型変数rに束縛していますので、一時オブジェクトの生存期間はrの生存期間と同じに延長、つまり範囲forを抜けるまで有効とされます。

c++

1// 元コード 2Hoge h; 3for(auto& str : h.get()) 4{ 5 std::cout << str << "\n"; 6} 7 8// 等価なコード(C++11仕様) 9Hoge h; 10{ 11 // rの型は std::vector<std::string>&& 12 auto && r = h.get(); // ★ 13 14 for (auto b = begin(r), e = end(r); b != e; ++b) { 15 // strの型は std::string& 16 auto & str = *b; 17 std::cout << str << "\n"; 18 } 19}

投稿2020/08/31 02:40

yohhoy

総合スコア6191

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

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

ttact

2020/08/31 02:46

わかりやすい説明ありがとうございます。 回答順がyumetodoさんの方が先だったことと、一時オブジェクトの寿命延長が規格で言及されている箇所を指摘して頂けたので、申し訳ないのですがyumetodoさんの回答をベストアンサーにさせて頂きました。 yohhoyさんのコード変換部はわかりやすく助かりました。
guest

0

ベストアンサー

結論から言うと問題ありません。

そのcpprefjpはC++11の解説ページなのでC++20現在はもうちょっと同等コードが変わっていますが基本的なことは変化していません。

https://timsong-cpp.github.io/cppwp/n4861/stmt.ranged#1

The range-based for statement

for ( init-statementopt for-range-declaration : for-range-initializer ) statement

is equivalent to

{
init-statementopt
auto &&range = for-range-initializer ;
auto begin = begin-expr ;
auto end = end-expr ;
for ( ; begin != end; ++begin ) {
for-range-declaration = * begin ;
statement
}
}

つまり、auto &&range = for-range-initializerのときに一時オブジェクトの寿命延長が発生します。

https://timsong-cpp.github.io/cppwp/n4861/class.temporary#2.1

2 The materialization of a temporary object is generally delayed as long as possible in order to avoid creating unnecessary temporary objects.

[ Note: Temporary objects are materialized:

(2.1)

when binding a reference to a prvalue ([[dcl.init.ref]](https://timsong-cpp.github.io/cppwp/n4861/dcl.init.ref), [[expr.type.conv]](https://timsong-cpp.github.io/cppwp/n4861/expr.type.conv), [[expr.dynamic.cast]](https://timsong-cpp.github.io/cppwp/n4861/expr.dynamic.cast), [[expr.static.cast]](https://timsong-cpp.github.io/cppwp/n4861/expr.static.cast), [[expr.const.cast]](https://timsong-cpp.github.io/cppwp/n4861/expr.const.cast), [[expr.cast]](https://timsong-cpp.github.io/cppwp/n4861/expr.cast)),

このため問題ないわけです。

問題となるケースはcpprefjpの「for-range-initializerに渡したものの寿命が切れてしまう場合」の項に書いたように、寿命延長が発生しないケースです。ぜひご確認ください。

投稿2020/08/31 02:35

yumetodo

総合スコア5852

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

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

ttact

2020/08/31 02:47 編集

わかりやすく信頼できる解説をありがとうございます。 一次オブジェクトの寿命延長の件についても、規格の言及箇所を示して頂けてとても助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問