メインコンテンツ

AUTOSAR C++14 Rule A15-1-1

Only instances of types derived from std::exception should be thrown

説明

ルール定義

Only instances of types derived from std::exception should be thrown.

根拠

汎用オブジェクトが例外として発生すると、コードの読み取りや再利用が困難になる可能性があります。2 つの異なる try-catch ブロックで例外が発生する次のコードについて考えます。

try{
	//..
	throw 1; // 1 means logic error;
}
catch(...){
	//...
}
//...
try{
	//...
	throw  std::logic_error{"Logic Error"};
}
catch(std::exception& e){
	//..
}
1 つ目のコード ブロックでは、この例外の原因や意味が明確になっていません。このような曖昧な例外が、コードの読み取りや再利用を困難にする可能性があります。この種の汎用例外は、コードのどこかで発生した例外と競合する可能性もあり、例外の処理がより難しくなります。このルールは、このような汎用オブジェクトは例外オブジェクトとして受け入れられないとしています。

2 つ目のコード ブロックでは、固有のタイプのオブジェクトを例外として発生させることにより、例外の意味と原因が明確に伝達されています。このような throw ステートメントは、標準規則にも合致します。開発者の意図を明確に伝達し、標準規則に準拠し、固有のタイプの例外を発生させることにより、コードの読み取り、理解、および再利用が容易になります。

クラス std::exception は、特定のエラーに対応する固有の例外を発生させるための一貫したインターフェイスを提供します。これは、このインターフェイスを使用して例外を発生させるための標準規則です。コードを読みやすく、再利用可能にするには、std::exception から派生した特定のタイプのオブジェクトを例外として発生させます。std::exception タイプの汎用オブジェクトは固有にできません。このような例外はこのルールに違反します。

Polyspace 実装

  • Polyspace® は、発生するオブジェクトのタイプが std::exception からパブリックに派生したクラスではない場合に、throw ステートメントにフラグを設定します。

  • 発生するオブジェクトが多重継承階層の一部の場合は、Polyspace が、どの基底クラスも std::exception からパブリックに派生していないまたは基底クラスに std::exception が含まれていない場合に、オブジェクトにフラグを設定します。

  • catch ブロックに引数が含まれていない throw; ステートメントを使用する場合は、Polyspace が throw; ステートメントにフラグを設定しません。

トラブルシューティング

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

すべて展開する

この例では、Polyspace が非準拠クラス階層のオブジェクトを発生させる throw ステートメントにどのようにフラグを設定するかを示します。

#include <stdexcept>
#include <memory>

class ConventionalException : public std::logic_error{
public:
	using std::logic_error::logic_error;
};
class CustomException {};
class CustomException_derived : public CustomException {};
class PrivateDerived : private std::exception {};
class ProtectedDerived : protected std::exception {};
class MultipleInheritenceCompliant : 
	public ConventionalException, public CustomException {
public:
	MultipleInheritenceCompliant()
	: ConventionalException("Logic Error and Data Error") {
	}
};
class MultipleInheritenceNoncompliant :
	public ProtectedDerived, public CustomException {};

void Foo() {
	throw std::exception();   // Noncompliant 
	throw CustomException(); // Noncompliant
	throw CustomException_derived(); // Noncompliant 
	throw PrivateDerived();       // Noncompliant 
	throw ProtectedDerived();     // Noncompliant 
	throw MultipleInheritenceCompliant(); // Compliant
	throw MultipleInheritenceNoncompliant(); // Noncompliant
	throw ConventionalException{"Logic Error"};//Compliant
	throw std::make_shared<std::exception> // Noncompliant
	(std::logic_error("Logic Error")); 
}

  • Polyspace は、throw std::exception() ステートメントにフラグを設定します。これは、コード内で一意ではない可能性のある汎用 std::exception オブジェクトが発生するためです。

  • Polyspace は、throw CustomException() ステートメントにフラグを設定します。これは、クラス CustomExceptionstd::exception から派生していないためです。また、Polyspace は、同じ理由で、throw CustomException_derived() ステートメントにフラグを設定します。

  • Polyspace は、throw PrivateDerived() ステートメントにフラグを設定します。これは、クラス PrivateDerivedstd::exception からプライベートに派生しているためです。std::exceptionPrivateDerived 間のプライベート継承が原因で、この例外を catch(std::exception& e) ブロックを使用してキャッチすることはできません。Polyspace は、同じ理由で、throw ProtectedDerived() ステートメントにフラグを設定します。

  • Polyspace は、throw MultipleInheritenceNoncompliant() ステートメントにフラグを設定します。これは、クラス MultipleInheritenceNoncompliantstd::exception からパブリックに派生していないためです。

  • Polyspace は、 throw std::make_shared<std::exception>(std::logic_error("Logic Error")) ステートメントにフラグを設定します。これは、このステートメントが、std::shared_ptr から派生していない std::exception オブジェクトを例外として発生させるためです。

  • Polyspace は、throw MultipleInheritenceCompliant() ステートメントと throw ConventionalException{"Logic Error"} ステートメントにフラグを設定しません。これは、これらのステートメントが、std::exception からパブリックに派生したクラスのオブジェクトを発生させるためです。

この例では、Polyspace が catch ブロック内の throw ステートメントにどのようにフラグを設定するかを示します。

#include <memory>
#include <stdexcept>
class MyException : public std::logic_error
{
public:
	using std::logic_error::logic_error;
	// Implementation
};
void catch_and_rethrow() {
	try {
		/* ... */
	}catch (std::exception e) {
		throw; // Compliant
		throw e; // Noncompliant		
	}catch (std::exception& e) {
		throw e; // Noncompliant
		throw;   // Compliant
	}catch (MyException& Error) {
		throw Error; // Compliant
	}
}
  • catch ブロック内の空の throw; ステートメントは、実行時の状況に応じて、異なるタイプの例外を発生させる可能性があります。Polyspace は、実行時の状況に固有の情報を使用せずに throw; ステートメントを解析するため、空の throw; ステートメントが発生する可能性のあるオブジェクトの種類を特定できません。Polyspace は、catch ブロック内の throw; ステートメントにフラグを設定しません。

  • Polyspace は、throw e ステートメントにフラグを設定します。これは、std::exception オブジェクト e を例外として発生させるためです。std::exception クラスへの参照またはそのクラスのインスタンスを受け入れる catch ブロック内のこのような throw ステートメントは避けてください。

  • Polyspace は、throw Error ステートメントにフラグを設定しません。これは、std::exception から派生したクラス MyException のオブジェクトを発生させるためです。

チェック情報

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

バージョン履歴

R2020b で導入