AUTOSAR C++14 Rule A12-8-2

Пользовательская копия и операторы присваивания перемещения должны использовать пользовательскую функцию подкачки без бросков

Описание

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

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

Объяснение

Наивная копия или оператор присваивания перемещения, который реализован, не используя подкачку функциональная сила, следуют за шаблоном в этом коде:

class A{
	//...
	A & operator=(const A & rhs)
	{
		if (this != &rhs) // check for self assignment
		{
			// release resource in lhs
			
			// Allocate resource for modified lhs
			
			
			// Copy or move the resources from rhs to lhs
			
		}

		return *this;
	}
private:
	//resources
	int* mArray;
};
Такая наивная реализация копии или оператора присваивания перемещения не может обеспечить сильную безопасность исключения, потому что, если какая-либо из операций повышает исключение, левый операнд не может вернуться назад к его исходному состоянию. Предыдущий шаблон также неэффективен, потому что он требует проверки на самоприсвоение. Дублирование кода между такой копией или оператором присваивания перемещения и копией или конструктором перемещения делает код трудным обеспечить.

Чтобы решить эти вопросы, используйте пользовательский swap функции, которые не повышают исключения. Рассмотрите этот шаблон:

class A{
	//...
	A & operator=(A rhs)
	{
		Swap(*this,rhs);
	}
	friend void Swap(A& lhs, A& rhs) noexcept{
		//...
	}
private:
	//resources
	int* mArray;
	
};
Эта реализация копии или оператора присваивания перемещения не делает попытку выделения или освобождения памяти. Вместо этого Это подкачивает ресурсы между левыми и правыми операндами путем вызова пользовательского noexcept функциональный Swap. Этот Swap функциональная сила быть реализованным путем использования std::swap функция. Преимущества этого шаблона:

  • Сильная безопасность исключения: Эта реализация копии или оператора присваивания перемещения делает временную копию правильного операнда при помощи копии или конструктора перемещения и подкачивает временную копию с левым операндом. Поскольку функциями перемещения и подкачки должен быть noexcept, только операция копии может повысить исключение. Если этот оператор повышает исключение, только временная копия правильного операнда может делаться недействительным. Состояние права или левого операнда остается нетронутым.

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

  • Эффективность: Путем устранения проверки по сравнению с самоприсвоением оператор более эффективен.

Чтобы реализовать копию или переместить оператор присваивания, используйте пользовательский noexcet подкачайте функции.

Реализация Polyspace

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

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

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

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

#include <utility>
#include <string>
class B
{
  public:
    B& operator=(const B& oth) & { // Noncompliant
      if (this != &oth)
      {
        ptr1 = new std::int32_t(*oth.ptr1);
        ptr2 = new std::int32_t(
          *oth.ptr2); // Exception thrown here results in
        // a memory leak of ptr1
      }

      return *this;
    }
    B& operator=(B&& oth) & noexcept { // Noncompliant
      if (this != &oth)
      {
        ptr1 = std::move(oth.ptr1);
        ptr2 = std::move(oth.ptr2);
        oth.ptr1 = nullptr;
        oth.ptr2 = nullptr;
      }

      return *this;
    }
private:
    std::int32_t* ptr1;
    std::int32_t* ptr2;
};

В этом примере, копии и операторе присваивания перемещения для класса B использует наивную реализацию вместо реализации копии-и-подкачки. Оператор копии и перемещения B неэффективен и не обеспечивает сильную безопасность исключения. Polyspace отмечает эти операторы как несовместимые.

#include <utility>
#include <string>
class C
{
  public:
    C(const C&) = default;
    C(C&&) = default;

    C& operator=(const C& oth) & {     //Noncompliant
      C tmp(oth);
      std::swap(ptr1, tmp.ptr1);       
      return *this;
    }
    C& operator=(C&& oth) & {          // Noncompliant
      C tmp(std::move(oth));
      std::swap(ptr1, tmp.ptr1);       
      return *this;
    }

  private:
    std::int32_t* ptr1;
};

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

#include <utility>
#include <string>

class D
{
  public:
    D(const D&) = default;
    D(D&&) = default;
    D& operator=(const D& oth) & {     // Noncompliant
      D tmp(oth);
      _swap_(*this,tmp);
      return *this;
    }
    D& operator=(D&& oth) & {          // Noncompliant
      D tmp(std::move(oth));
      _swap_(*this,tmp);
      return *this;
    }
	//...
	friend void _swap_(D& lhs, D& rhs){ // swap function not noexcept
	//...
	}
};

В этом примере, копии и операторе присваивания перемещения для класса D использует swap функция, которая не является noexcept. Эти операторы не обеспечивают сильную безопасность исключения. Polyspace отмечает их как несовместимых.

#include <utility>
#include <string>

class E
{
  public:
    E(const E&) = default;
    E(E&&) = default;

    E& operator=(const E& oth) & {     // Noncompliant
      E tmp(oth);
      swap(*this,tmp);
      return *this;
    }
    E& operator=(E&& oth) & {          // Noncompliant
      E tmp(std::move(oth));
      swap(*this,tmp);
      return *this;
    }

    // Member function swap
    void swap(E& lhs, E& rhs) noexcept {
      std::swap(lhs.ptr1, rhs.ptr1);
      std::swap(lhs.ptr2, rhs.ptr2);
    }

  private:
    std::int32_t* ptr1;
    std::int32_t* ptr2;
};

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

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

Группа: Специальные функции членства
Категория: консультация, автоматизированная
Введенный в R2021a