AUTOSAR C++14 Rule A6-2-1

Операторы назначения перемещения и копирования должны либо перемещать, либо соответственно копировать базовые классы и представители данных класса без каких-либо побочных эффектов

Описание

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

Операторы назначения перемещения и копирования должны либо перемещать, либо соответственно копировать базовые классы и представители данных класса без каких-либо побочных эффектов.

Объяснение

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

class C{
	//...
	C& operator=(const C& oth) { 
		value = oth.value / 2;
		return *this;		
	}
public:
	int value;
};

int main(){
	C a, b, c; 
	a.value = 48;
	// …
	b = a; // b.m = 24  
	c = b; // c.m = 12
	a = c; // a.m = 6
}
Во время каждого присвоения копии, value в целевом объекте становится половина value в исходном объекте. После трех последовательных операций копирования, a.value становится 6, что неожиданно. Алгоритмы ожидают перемещения и копирования операторов назначения, которые не изменяют инвариант объекта. Если у операторов переноса или копирования класса есть побочные эффекты, которые изменяют инвариант объекта, использование библиотек алгоритмов, таких как стандартная библиотека шаблонов (STL), может привести к неожиданным результатам.

Поскольку вы много раз используете назначения move и copy в коде, любой побочный эффект, создающий код, может сделать код медленнее и ресурсоемким. В операторе назначения перемещения код, который вызывает побочные эффекты, может также заставить компилятор использовать операцию копирования с каждым назначением, что неэффективно.

Для поддержания оптимальной и надежной эффективности во время переезда и копирования выполните только эти операции в операторах переезда и копирования:

  • Копирование или перемещение представителей данных и базовых классов.

  • Верните указатель *this.

  • Если возможно, установите объект moved-from в допустимое состояние.

Избегайте лишнего кода, который добавляет несвязанные побочные эффекты или накладную эффективность.

Реализация Polyspace

В теле оператора копирования или перемещения назначения Polyspace® не помечает эти операции:

  • Копирование или перемещение назначений.

  • Реляционные или сравнительные операции.

  • Изменение исходного объекта в операции перемещения.

  • Вызовы функции std::swap или эквивалентные пользовательские noexcept функции swap. Polyspace идентифицирует функции, которые эти сигнатуры как функции свопа: void T::swap(T&) или void [N::]swap(T&, T&). Первая сигнатура представляет представителю функцию T классов это принимает один аргумент. Вторая сигнатура представляет часть или статическую функцию в пространстве имен N это принимает два аргумента. Имя swap может быть нечувствительным к регистру и префиксированным или постфиксированным подчеркиванием.

  • Назначение и изменение static переменные.

Polyspace помечает любые другие операции в операторе копирования или перемещения назначения как нежелательный побочный эффект. Например, вызов пользовательской функции swap рассматривается как нежелательный побочный эффект, если функция swap не noexcept. Для аналогичного правила копирования и перемещения конструктора смотрите AUTOSAR C++14 Rule A12-8-1.

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

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

Примеры

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

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

#include<cstdint>
#include<iostream>
class B
{
public:
	B() : ptr(0) {}
	B& operator=(B&& oth) //Noncompliant
	{

		if(&oth == this) {
			return *this;
		}
		ptr = std::move(oth.ptr); 
		std::cout<<"Moved";
		return *this;
	}

private:
	std::int32_t* ptr;
};
class C
{
public:
	C(int t=0) : x(t) {}
	C& operator=(const C& oth)  // Noncompliant
	{
		if(&oth == this) {
			return *this;
		}
		x = oth.x % 2;         // This operation produces side-effect
		count++; //Not a side effect
		return *this;
	}

private:
	std::int32_t x;
	static std::int32_t count;

};
class D
{
public:
	D(const D&) = default;
	D(D&&) = default;

	D& operator=(const D& oth) & {     // Noncompliant
		D tmp(oth);
		swap(tmp);
		return *this;
	}
	
	// Member function swap
	void swap(D& rhs)  {
		//...
	}

private:
	std::int32_t x;
};
  • В качестве побочного эффекта оператор назначения перемещения класса B печатает строку в выход поток. Этот побочный эффект добавляет накладные расходы на эффективность операции перемещения. Если этот оператор std::cout<<"Moved" вызывает исключение, выполнение кода может неожиданно остановиться. Polyspace помечает оператор назначения перемещения и подсвечивает оператор.

  • Оператор назначения копирования C изменяет представитель данных x исходного объекта. Этот побочный эффект добавляет накладную эффективность. Неожиданное изменение представителей данных во время операций перемещения и копирования может сделать код несовместимым со стандартной библиотекой шаблонов и ввести ошибки во время разработки. Polyspace помечает оператор назначения копирования и подсвечивает оператор x = oth.x % 2. Увеличение размера статической переменной count не является побочным эффектом.

  • Оператор назначения копирования класса D вызывает пользовательскую функцию swap, вызываемую _swap_. Эта функция swap не noexcept. Если вызвано исключение из _swap_исключение является неожиданным побочным эффектом оператора назначения копии. Polyspace помечает конструктор копирования как несовместимый с этим правилом. Используйте пользовательскую функцию swap, которая noexcept.

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

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