CERT C++: OOP58-CPP

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

Описание

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

Операции копии не должны видоизменять источник object.[1]

Реализация Polyspace

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

Примеры

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

Проблема

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

Например, этот конструктор копии 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. Объектно-ориентированное программирование (OOP)
Введенный в R2019a

[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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