Main Content

AUTOSAR C++14 Rule A15-1-3

All thrown exceptions should be unique

Since R2020b

Description

Rule Definition

All thrown exceptions should be unique.

Rationale

If the same object is raised as exceptions in multiple places, handling these exceptions and debugging the code can be difficult. Raising unique exception objects simplifies the debugging process. Consider this code where multiple exceptions are raised.

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';	
		}
	}
}
The functions f1() and f2() raise the same exception, while f3() raises a unique exception. During debugging, you cannot determine if an exception arises from f1() or f2(). You know when an exception arises from f3(). To make the debugging process simpler, raise unique exceptions. An exception is unique if either of these conditions is true:

  • The exception type does not occur elsewhere in your project.

  • The error message or the error code does not occur elsewhere in your project.

Polyspace Implementation

Polyspace® highlights throw statements that raise the same class, enum value, integer, or constant literal as exceptions, and flags the final throw statement that raise the same object. You might want to raise the same exception in multiple places by using a preconstructed exception object. Polyspace does not flag throw statements that raise such preconstructed exception objects. If you raise the same literal object in multiple places, Polyspace does not flag it if the literal is not a constant or if the literal is hidden behind a variable.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

This example shows how Polyspace flags nonunique exceptions.

#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
}

  • The function foo0() raises two different types of objects as exceptions. Polyspace does not flag the throw statements in foo0().

  • The function foo1() raises two exceptions that evaluate to be the same object during run-time. Because Polyspace analyzes the exception objects without runtime information, the exceptions appear unique and Polyspace does not flag the throw statements.

  • The function foo2() raises two exceptions that evaluate to be different objects at run-time. Because Polyspace analyzes the exception objects without run-time information, the exceptions appear nonunique. Polyspace highlights the throw statements in foo2() and flags the final the throw statement.

  • The function foo3() raises three exceptions by using objects that are the same at compile time. Polyspace highlights the throw statements in foo3() and flags the final the throw statement. For the same reason, the final throw statements in foo4() and foo5() are flagged.

Check Information

Group: Exception handling
Category: Advisory, Automated

Version History

Introduced in R2020b