メインコンテンツ

AUTOSAR C++14 Rule A8-4-4

Multiple output values from a function should be returned as a struct or tuple

説明

ルール定義

Multiple output values from a function should be returned as a struct or tuple.

根拠

C++ 関数の return ステートメントは単一の変数に格納された値のみを返すことができます。しかし、呼び出し元スコープの任意の数の追加の変数に格納された値を参照で渡して、呼び出し先の本体でその値を変更すると、呼び出し先でその変数値を変更できます。たとえば、関数 foo を考えてみましょう。

int foo(int x, int& y)
{
  int z;
  y = x*x;
  z = x*x*x;
  return z;
}

関数 foo は実質的に 2 つの整数値を返しています。入力パラメーター x の 2 乗 (参照によって返す)、および入力パラメーター x の 3 乗 (return ステートメントを使用してコピーによって返す) です。同時に両方の手法を使用して複数の値を返すと、関数インターフェイスが複雑になり、コードの読みやすさと保守のしやすさが損なわれる可能性があります。代わりに、すべての戻り値を 1 つの struct または tuple に格納し、return ステートメントを使用して返すと、簡潔で統一されたインターフェイスになります。

struct または tuple を返す return ステートメントを使用すると、1 つのメモリ位置から別のメモリ位置にコピーすることにより計算量が多くなる可能性があります。多くのコンパイラでは戻り値の最適化をサポートして、このような計算量の多いコピーを取り除くことができ、このような return に関するオーバーヘッドが少ないかまたはない実行可能コードが得られます。

複数の値を返すために struct と tuple のどちらを使用するか判断するため、以下を検討してください。

  • 戻り値が抽象型の場合は struct の使用をお勧めします。抽象データ型の各構成要素にカスタム名を付けることができるからです。

  • タプルを使う場合、返された tuple を呼び出しサイトでは std::tie を使用して簡単に処理できるので作業が容易になります。std::tie メソッドは、tuple の要素を呼び出し元の既存のローカル変数に直接入れます。

メモ

このルールは std::pair にも当てはまります。これはちょうど 2 つの要素からなる特殊な tuple です。

Polyspace 実装

チェッカーは、次の 2 つの条件のいずれかを満たす関数宣言にフラグを設定します。

  • 関数の戻り値の型が void 以外であり、少なくとも 1 つの非定数参照パラメーターが使用されている。

  • 関数に複数の非定数参照パラメーターがある。

使用法のメモと制限:

  • チェッカーはこのルールに違反する純粋バーチャル関数にフラグを設定します。このような関数にフラグが設定されるのは、純粋バーチャル関数のどの実装でもこのルールに準拠するためには、純粋バーチャル関数自体のインターフェイスがこのルールに準拠しなければならないからです。

  • チェッカーは、このルールに違反する演算子に対してはフラグを設定しません。

トラブルシューティング

ルール違反が想定されるものの、Polyspace® から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

#include <tuple>


int Divide1(int dividend, // Noncompliant, remainder returned as reference parameter 
			int divisor, int& remainder)   
{
  remainder = dividend % divisor;
  return dividend / divisor;
}

// Compliant, quotient and remainder combined into a tuple
std::tuple<int, int> Divide2(int dividend, int divisor)  
{
  return std::make_tuple(dividend / divisor, dividend % divisor);
}

int main()
{
  int quotient, remainder;
  // store in local variables
  std::tie(quotient, remainder) = Divide2(26, 5); 
  return 0;
}

関数 Divide1 では商が戻り値で、剰余が非定数参照パラメーターです。void 以外の戻り値で非定数参照パラメーターがある場合、このコーディング ルールに違反します。

関数 Divide2 は商と剰余を組み合わせてタプルにし、その tuple を返します。このコード パターンはルールに準拠しています。

struct fraction {
  int quotient;
  int remainder;
} ;



int Divide1(int dividend, // Noncompliant, quotient and remainder returned as reference parameters
			int divisor, int& quotient, int& remainder)   
{
  quotient = dividend / divisor;
  remainder = dividend % divisor;
}

// Compliant, quotient and remainder combined into a struct
fraction Divide2(int dividend, int divisor)  
{
  fraction answer;
  answer.quotient = dividend / divisor;
  answer.remainder = dividend % divisor;
  return answer;
}

int main()
{
  fraction answer;
  answer = Divide2(26,5);
  return 0;
}

関数 Divide1 では商と剰余の両方が非定数参照パラメーターです。複数の非定数参照パラメーターを使用すると、このコーディング ルールに違反します。

関数 Divide2 は商と剰余を組み合わせて struct にし、その struct を返します。このコード パターンはルールに準拠しています。

チェック情報

グループ: 宣言子
カテゴリ: Advisory、Automated

バージョン履歴

R2020b で導入