exponenta event banner

CERT C++: OOP58-CPP

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

Описание

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

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

Реализация Polyspace

Эта проверка проверяет наличие операции копирования, изменяющей исходный операнд.

Примеры

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

Проблема

Операция копирования, изменяющая исходный операнд, происходит, когда конструктор копии или оператор назначения копии изменяет изменяемый представитель данных его исходного операнда.

Для образца, этот конструктор копирования A изменяет представитель данных m его исходного операнда other:

class A {
  mutable int m;
   
public:
 ...
  A(const A &other) : m(other.m) {
    other.m = 0; //Modification of source
  }
}

Риск

Операция копирования с конструктором копирования (или оператором назначения копирования):

className new_object = old_object; //Calls copy constructor of className
копирует его исходный операнд old_object на операнд назначения new_object. После операции вы ожидаете, что операнд назначения будет копией немодифицированного операнда источника. Если исходный операнд изменяется во время копирования, это предположение нарушается.

Зафиксировать

Не изменяйте исходный операнд в операции копирования.

Если вы изменяете исходный операнд в конструкторе копирования для реализации операции перемещения, используйте вместо этого конструктор перемещения. Перемещение конструкторов определяется в стандарте C++ 11 и более поздних версиях.

Пример - Копировать конструктор, изменяющий источник
#include <algorithm>
#include <vector>
 
class A {
  mutable int m;
   
public:
  A() : m(0) {}
  explicit A(int m) : m(m) {}
   
  A(const A &other) : m(other.m) {
    other.m = 0;
  }
   
  A& operator=(const A &other) {
    if (&other != this) {
      m = other.m;
      other.m = 0;
    }
    return *this;
  }
   
  int get_m() const { return m; }
};
 
void f() {
  std::vector<A> v{10};
  A obj(12);
  std::fill(v.begin(), v.end(), obj);
}

В этом примере вектор из десяти объектов типа A создается. The std::fill функция копирует объект типа A, который имеет представителя данных со значением 12, для каждого из десяти объектов. После этой операции можно ожидать, что все десять объектов в векторе имеют представитель данных со значением 12.

Однако первая копия изменяет представитель данных источника на значение 0. Остальные девять копий копируют это значение. После std::fill вызов, первый объект в векторе имеет представитель данных со значением 12, а остальные объекты имеют представители данных со значением 0.

Коррекция - Используйте Конструктор Перемещения для Изменения Источника

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

В этом исправленном примере конструктор копирования и оператор назначения копирования класса A не изменять представитель данных m. Отдельный конструктор перемещения изменяет исходный операнд.

#include <algorithm>
#include <vector>
 
class A {
  int m;
   
public:
  A() : m(0) {}
  explicit A(int m) : m(m) {}
   
  A(const A &other) : m(other.m) {}
  A(A &&other) : m(other.m) { other.m = 0; }
   
  A& operator=(const A &other) {
    if (&other != this) {
      m = other.m;
    }
    return *this;
  }
  
  //Move constructor
  A& operator=(A &&other) {
    m = other.m;
    other.m = 0;
    return *this;
  }
   
  int get_m() const { return m; }
};
 
void f() {
  std::vector<A> v{10};
  A obj(12);
  std::fill(v.begin(), v.end(), obj);
}

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

Группа: 09. Объектно-ориентированное программирование (OOP)
Введенный в R2019a

[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.