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

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

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

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

Q&A

解決済

3回答

17208閲覧

C++ - 関数の返り値が2つ以上ある場合は tuple より引数経由のほうがよい?

tiitoi

総合スコア21956

C++

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

0グッド

0クリップ

投稿2019/04/02 14:05

編集2019/04/02 14:13

環境

  • C++11
  • Visual Studio 2017

質問内容

返り値が2つ以上の場合、Python では tuple を使って返すのが一般的ですが、C++ のライブラリ (例: OpenCV) の関数を見ていると、引数経由で返すものが多く、tuple を使うものはほぼ見かけません。

引数経由だと入力と出力がわかりづらくなるので、可読性の面ではタプルで返すほうが直感的のような気がします。

C++ の場合は、タプルで複数の返り値を返すということは、パフォーマンス等の面で不利になってしまう等のなんらかの事情があり、非推奨なのでしょうか?

cpp

1#include <iostream> 2#include <tuple> 3 4 5// 引数で渡すタイプ 6void divmod1(int a, int b, int &q, int &r) 7{ 8 q = a / b; 9 r = a % b; 10} 11 12// 返り値で渡すタイプ 13std::tuple<int, int> divmod2(int a, int b) 14{ 15 return std::make_tuple(a / b, a % b); 16} 17 18int main() 19{ 20 int q, r; 21 22 divmod1(10, 3, q, r); 23 std::cout << "q: " << q << ", r: " << r << std::endl; 24 // q: 3, r: 1 25 26 std::tie(q, r) = divmod2(10, 3); 27 std::cout << "q: " << q << ", r: " << r << std::endl; 28 // q: 3, r: 1 29}

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

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

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

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

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

guest

回答3

0

ベストアンサー

こんにちは。

ちょっと前まで(とは言っても2011年頃ですから、既に結構たってます)、C++のSTLにstd::tuppleが無かったからと思います。今も、C++11非対応なコンパイラも生きていると思いますので、OpenCVは新しい機能への対応をわざわざやっていないということかも知れないです。

今なら(C++17以降)であれば、構造化束縛が便利そうです。(私はまだ使ったことはないのですが。)

投稿2019/04/02 14:14

Chironian

総合スコア23272

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

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

tiitoi

2019/04/02 14:24

迅速がご回答ありがとうございます。 互換性等の理由からあまり見かけないのですね。 ご紹介いただいた構造化束縛は、便利そうなので是非使ってみたいです。
guest

0

解決済みですが。C++の中では、tuple自体新しいものなので戻り値に使うという例自体多くは見ません。

参考までに

今時のC++の中でどうなるかはわかりませんけど、参照を使って引数経由で値を返すというのは2つ目的があります。一つはご提示の通り、複数の場合に対応するためです。ただし、もう一つ意味があります。

少なくともCやアセンブラでは大きなサイズの構造体(相当)データを値渡しすることは望ましくありません。このために、参照経由としているケースがあります。

というのも、高級言語では簡単に記述できても、機械語レベルで考えると結構な手間になりえるためです。例えば、構造体のデータサイズなんて簡単に大きくできます。一方、CPUが一度に処理できるデータサイズは基本的にレジスタに収まる範囲だけです。32bitCPUで考えれば、4kバイトの領域をコピーするために1k回の反復処理が内部的に行われるわけです。ですから、値渡しでなく参照渡し記述とした結果引数経由となる傾向にあります。

投稿2019/04/02 14:49

HogeAnimalLover

総合スコア4830

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

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

tiitoi

2019/04/02 14:55

ご回答ありがとうございます。 ハードウェアの観点から考えたことはなかったので、とても参考になります。 情報ありがとうございました。
Chironian

2019/04/02 19:27

HogeAnimalLoverさん RVO、NRVOに対応しているC++コンパイラが結構多いそうです。 https://blog.kmc.gr.jp/entry/2014/12/20/231430 この最適化が有効であれば巨大なデータを効率よく返却できます。なので、多少大きめのインスタンスでも戻り値で返却することが意外に多いです。(RVO/NRVOを知った時、かなり衝撃でした。) 更にC++17でコピー無しを保証する仕様が導入されているそうです。 https://faithandbrave.hateblo.jp/entry/2017/01/24/161342
HogeAnimalLover

2019/04/03 14:51 編集

Chironianさん ご指摘ありがとうございます。「今時のC++ならば多分そのようなものはあるだろう」と思ってはいましたが、やはり実在するのですね。調査不足でした。それにしてもC++は0x11以降まるでついていけていないなOTL
guest

0

C++標準ライブラリにタプル型(std::tuple)が導入されたのはC++11以降と比較的新しいため、OpenCVのように歴史の長いライブラリでは積極的に切り替えてまでは利用されていません。
(OpenCVはもともとC言語APIから始まったほど歴史の古いライブラリですから、保守的にAPIを移行しているようです。最新のOpenCV 4系でようやくC APIが廃止されました。)

引数経由だと入力と出力がわかりづらくなるので、可読性の面ではタプルで返すほうが直感的のような気がします。

はい。最新のC++17では 構造化束縛(structured bindings) も導入されたため、Python風の多値返却も可読性高く記述できるようになっています。

cpp

1#include <string> 2#include <tuple> 3 4// タプル(int型, string型, double型)を返す関数 5std::tuple<int, std::string, double> func(); 6 7// 構造化束縛により戻り値タプルから個別変数へ代入 8auto [vi, s, vd] = func(); 9// vi := int型変数 10// s := string型変数 11// vd := double型変数

C++ Core Guildlinesでも F.21: To return multiple "out" values, prefer returning a struct or tuple にてタプル(や構造体)による多値返却スタイルを推奨しています。

投稿2019/04/02 14:17

編集2019/04/06 12:29
yohhoy

総合スコア6189

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

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

tiitoi

2019/04/02 14:23

迅速がご回答ありがとうございます。 互換性等の理由からあまり見かけないのですね。 構造化束縛は python-like にかけて良さそうですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問