AUTOSAR C++14 Rule A6-2-2

Операторы выражения не должны быть явными вызовами только конструкторов временных объектов

Описание

Определение правила

Операторы выражения не должны быть явными вызовами только конструкторов временных объектов.

Объяснение

Объекты, которые компилятор создает на короткое время, а затем удаляет, являются временными объектами. Компилятор может создавать временные объекты для определенных целей, таких как:

  • Инициализация ссылок

  • Хранение значений, возвращаемых функциями

  • Типовое литье

  • Обработка исключений

Временные объекты уничтожаются, когда выражение, которое требует их конструкции, полностью оценивается. Например, при оценке выражения sum = a*b+cкомпилятор создает два временных объекта для хранения результатов операций умножения и сложения. После оценки выражения оба временных объекта уничтожаются. Их возможности ограничены оператором выражения.

Если выражение является явным вызовом конструктора, опускающего имя объекта, компилятор создает временный объект, который немедленно уничтожается. Такой явный вызов конструктора может указать, что:

  • Вы непреднамеренно опускали имя объекта.

  • Вы ожидали, что неназванная переменная останется в возможности до конца блока объявления.

Рассмотрим этот фрагмент кода, где a lock_guard создается объект.

void foo(){
std::mutex mymutex;
std::mutex mymutex2;
std::lock_guard<std::mutex> lock{mymutex};
std::lock_guard<std::mutex> {mymutex2};
//...
}
Первое объявление создает lock_guard объект с именем lock. Объект lock защищает mymutex от параллельного доступа несколькими потоками до конца текущего блока. Вторая декларация пытается получить аналогичную защиту для mymutex2. Потому что lock_guard объект в этом случае не называется, он уничтожается сразу после оператора объявления. Возможно, непреднамеренно, mymutex2 остается незащищенным от проблем параллелизма.

Избегайте операторов выражения, которые являются только явным вызовом конструктора. Чтобы реализовать шаблон Resource Acquisition Is Initialization (RAII), используйте именованные объекты.

Реализация Polyspace

Polyspace® помечает любой оператор выражения, который создает неназванный объект и не использует его. Вы можете создавать неназванные временные объекты, когда используете объекты в операторе выражения объявления. Например, временный объект, который используется в качестве возврата функции или в правой части назначения, соответствует этому правилу.

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

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

Этот код показывает, как Polyspace помечает операторы, которые являются только явными вызовами конструктора.

#include <cstdint>
#include <fstream>
#include <string>
class MyException {
	MyException(const std::string &);
};
void with_exception() {
	MyException("Exception");              //Noncompliant
	throw MyException("Exception");        //Compliant 
	
};  

Polyspace помечает оператор выражения, который создает неназванный временный объект и не использует его. Если вы используете временный объект в операторе, оператор соответствует правилу. Для примера оператор MyException("Exception"); помечен, поскольку неназванный объект, созданный явным вызовом конструктора MyException() не используется в операторе. Оператор throw MyException("Exception"); не помечен, поскольку объект без имени используется в качестве аргумента для throw.

Компиляторы уничтожают неназванный lock_guard объект сразу после оператора объявления. Безымянный lock_guard объекты не могут защитить mutex объекты из проблем параллелизма. Polyspace помечает оператор, когда объявляет неназванное lock_guard объект. Рассмотрим этот код:

#include <cstdint>
#include <mutex>
class A {
public:
	void SetValue1(std::int32_t value) {
		std::lock_guard<std::mutex> {mutex1}; //Noncompliant
		private_value = value;
	}

	void SetValue2(std::int32_t value) {
		std::lock_guard<std::mutex> lock{mutex2}; //Compliant
		private_value = value;
	}
private:
	mutable std::mutex mutex1;
	mutable std::mutex mutex2;
	std::int32_t private_value;
};

  • Оператор std::lock_guard<std::mutex> {mutex1}; объявляет неназванную lock_guard объект. Polyspace помечает оператор.

  • Оператор std::lock_guard<std::mutex> lock{mutex2}; не помечен, потому что lock_guard объект имеет имя.

Проверяйте информацию

Группа: Операторы
Категория: Необходимый, Автоматизированный