メインコンテンツ

AUTOSAR C++14 Rule A15-1-3

All thrown exceptions should be unique

説明

ルール定義

All thrown exceptions should be unique.

根拠

同じオブジェクトが複数の場所で例外として発生した場合、これらの例外の処理とコードのデバッグが困難になる可能性があります。一意の例外オブジェクトを発生させると、デバッグ プロセスが簡略化されます。複数の例外が発生する次のコードについて考えます。

void f1(){
	//...
	throw std::logic_error("Error");
}
void f2(){
	//...
	throw std::logic_error("Error");
}
void f3(){
	//...
	throw std::logic_error("f3: Unexpected Condition");
}
int main(){
	try{
		f1();
		f2();
		f3();
		catch(std::logic_error& e){
			std::cout << e.what() << '\n';	
		}
	}
}
関数の f1()f2() は同じ例外を発生させますが、f3() は一意の例外を発生させます。デバッグ中は、例外が f1()f2() のどちらから発生したかを判断できません。例外が f3() から発生した場合には判断がつきます。デバッギング プロセスを簡略化するには、一意の例外を発生させます。以下の条件のどちらかが当てはまる場合、例外は一意です。

  • 例外の型がプロジェクト内の他の場所で発生していない。

  • エラー メッセージまたはエラー コードがプロジェクト内の他の場所で発生していない。

Polyspace 実装

Polyspace® は、同じクラス、列挙値、整数、または定数リテラルを例外として発生させる throw ステートメントを強調表示し、同じオブジェクトを発生させる最後のスロー ステートメントにフラグを設定します。事前構築された例外オブジェクトを使用して、同じ例外を複数の場所で発生させるとします。Polyspace は、このような事前構築された例外オブジェクトを発生させる throw ステートメントにフラグを設定しません。同じリテラル オブジェクトを複数の場所で発生させる場合、そのリテラルが定数でないか、リテラルが変数の後ろに隠れるのであれば、Polyspace はそのリテラル オブジェクトにフラグを設定しません。

トラブルシューティング

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

すべて展開する

この例では、Polyspace は一意でない例外にフラグを設定します。

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>

int readLog();
enum ENUM {
	ENUM_VALUE_13 = 13,
	ENUM_VALUE_14 = 14,
};  
const char* value_gen(int i) {
	if (i % 2 == 0) return "value_gen-0";
	else return "value_gen-1";
}
class CustomException : public std::invalid_argument {
public:
	CustomException() : std::invalid_argument(value_gen(readLog())) {}
};
int foo0(){
	//...
		throw std::logic_error("Invalid Logic"); // Compliant
	//...
		throw std::runtime_error("Runtime Error"); // Compliant
}
int foo1(){
	//...
		throw std::logic_error(value_gen(0)); 
	//...
		throw std::logic_error(value_gen(2));  
}
int foo2(){
//..
		throw CustomException();
//..
		throw CustomException(); // Noncompliant
}

	int foo3(){
	const int localConstInt42 = 42;
	//..
		throw 42;
	//...
		throw localConstInt42; //Noncompliant
}
int foo4(){
	//..
		throw "RUNTIME_ERROR"; 
	//...
		throw "RUNTIME_ERROR"; // Noncompliant
}
int foo5(){
	//...
		throw ENUM_VALUE_14;
	//...
		throw ENUM_VALUE_14; // Noncompliant
}

  • 関数 foo0() は 2 種類のオブジェクトを例外として発生させます。Polyspace は foo0() 内の throw ステートメントにフラグを設定しません。

  • 関数 foo1() は、実行時に同じオブジェクトとして評価される 2 つの例外を発生させます。Polyspace は実行時情報を使用せずに例外オブジェクトを解析するため、例外は一意であると見なされ、Polyspace はスロー ステートメントにフラグを設定しません。

  • 関数 foo2() は、実行時に別々のオブジェクトとして評価される 2 つの例外を発生させます。Polyspace は実行時情報を使用せずに例外オブジェクトを解析するため、例外は一意ではないと見なされ、Polyspace は、foo2() 内のスロー ステートメントを強調表示し、最後のスロー ステートメントにフラグを設定します。

  • 関数 foo3() は、コンパイル時に同じオブジェクトを使用して 3 つの例外を発生させます。Polyspace は、foo3() 内のスロー ステートメントを強調表示し、最後のスロー ステートメントにフラグを設定します。同じ理由で、foo4()foo5() 内の最後の throw ステートメントにもフラグが設定されます。

チェック情報

グループ: Exception handling
カテゴリ: Advisory、Automated

バージョン履歴

R2020b で導入