AUTOSAR C++14 Rule A15-1-4

Если функция выйдет за исключением, то перед броском, функция должна поместить все объекты/ресурсы, которые функция создала в допустимых состояниях, или это должно удалить их.

Описание

Управляйте определением

Если функция выйдет за исключением, то перед броском, функция должна поместить все объекты/ресурсы, которые функция создала в допустимых состояниях, или это должно удалить их.

Объяснение

Когда функция выходит за исключением, любым ресурсом или памятью, что выделенная функция не может быть правильно освобождена. Рассмотрите этот код:

FILE* FilePtr; 
//...
void foo(){
	FilePtr = fopen("some_file.txt", "r");
//...
	if(/*error condition*/)
	throw ERROR_CODE;
	
	delete FilePtr;
}
Выделенный указатель файла предназначается, чтобы быть освобожденным перед функциональным выполнением концов. Но когда исключение происходит, функциональные выходы, не удаляя указатель, который приводит к утечке памяти. Чтобы избежать утечек памяти, функция должна установить все ресурсы, которые она выделяет допустимому состоянию, прежде чем она выйдет из осциллографа. Например, в предыдущем примере кода, функция должна удалить указатель FilePtr перед throw оператор.

Вместо того, чтобы вручную отследить выделение и освобождение ресурсов, должна следовать лучшая практика, "Захват Ресурса Является Инициализацией" (RAII), или "Конструктор Получает, Релизы Деструктора" (КАДРЫ) шаблон разработки. В этом шаблоне распределение ресурсов выполняется в конструкторах, и освобождение ресурса выполняется в деструкторах. Жизненным циклом ресурсов управляют ограниченные осциллографом объекты в этом шаблоне. Когда функции достигают конца своего осциллографа, полученные средства правильно высвобождены. Рассмотрите этот код:

void releaseFile(std::FILE* fp) { std::fclose(fp); }
std::unique_ptr<std::FILE, decltype(&releaseFile)> FilePtr;
//...
void foo(){
	FilePtr(std::fopen("some_file.txt"),&releaseFile);
//...
	if(/*error condition*/)
	throw ERROR_CODE;
}
Здесь, уникальный указатель FilePTR вызывает функциональный releaseFile удалить выделенный ресурс однажды функциональный foo достигает конца его осциллографа, или обычно или из-за необработанного исключения.

Интеллектуальные указатели C++, такие как std::unique_ptr и std::shared_ptr следуйте за шаблоном RAII. Они упрощают управление жизненный цикл ресурсов во время обработки исключений. Избегайте использования необработанных указателей, когда это возможно.

Реализация Polyspace

Polyspace® отмечает непойманный throw оператор в, если оператор может привести к утечке ресурсов. Например,

  • throw оператор вне try блок отмечается, если выделенные ресурсы не освобождены перед оператором.

  • throw оператор в catch блок отмечается, если ресурсы не освобождены прежде, чем повысить исключение.

Polyspace не отмечает throw оператор, если это в try блокируйтесь, который имеет соответствующий обработчик или если исключение повышено прежде, чем выделить ресурсы.

Поиск и устранение проблем

Если вы ожидаете нарушение правила, но не видите его, относитесь, чтобы Диагностировать, Почему Кодирующие Стандартные Нарушения Не Появляются как ожидалось.

Примеры

развернуть все

#include <cstdint>
#include <memory>
#include <stdexcept>
extern int sensorFlag() noexcept;
namespace Noncompliant{
	void func(){
		int* intPtr = new int;
		int data = sensorFlag();
		if(data==-1)//Error
		throw std::runtime_error("Unexpected value");//Noncompliant
		//...
		delete intPtr;
	}
}
namespace Compliant{
	void func(){
		int* intPtr = new int;
		int data = sensorFlag();
		if(data==-1){//Error
			delete intPtr;
			throw std::runtime_error("Unexpected value");//Compliant
		}
		//...
		delete intPtr;
	}
}
namespace BestPractice{
	void func(){
		std::unique_ptr<int> intPtr = std::make_unique<int>();
		int data = sensorFlag();
		if(data==-1){//Error
			throw std::runtime_error("Unexpected value");//Compliant
		}
		//...
		
	}
}

В этом примере, функциональном Noncompliant::func() управляет необработанным указателем inPtr. Функция выделяет память для него, и затем выпускает память после некоторых операций. Функция выходит за исключением когда data -1. В этом случае, функциональные выходы прежде, чем выпустить выделенную память, приводя к утечке памяти. Чтобы предотвратить утечку памяти, выделенная память должна быть выпущена прежде, чем повысить исключение, как показано в Compliant::func.

Лучшая практика должна следовать шаблону разработки RAII и использовать unique_ptr вместо необработанного указателя. BestPractice::func показывает реализацию func это следует за шаблоном RAII. В этом случае жизненный цикл памяти управляем самим объектом. Таким образом, однажды func вне осциллографа, интеллектуальный указатель intPtr удаляет себя и выпускает память. Поскольку управление памятью выполняется правильно интеллектуальным указателем, BestPractice::func более просто и более безопасен.