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 создается. 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. Объектно-ориентированное программирование (ООП)
Представлен в R2019a

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

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

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