exponenta event banner

Самостоятельное назначение не протестировано в операторе

Оператор копирования назначения не проверяет самоназначение

Описание

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

Риск

Самостоятельное назначение вызывает ненужное копирование. Хотя маловероятно, что объект назначается самому себе, из-за наложения псевдонимов вы или пользователи вашего класса не всегда могут обнаружить самостоятельное назначение.

Самостоятельное назначение может привести к тонким ошибкам, если элемент данных является указателем, а память выделяется указателю динамически. В операторе присвоения копирования обычно выполняются следующие шаги:

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

    delete ptr;
    
  2. Выделение новой памяти указателю. Инициализируйте новую ячейку памяти с содержимым, полученным из аргумента оператора.

     ptr = new ptrType(*(opArgument.ptr));
    

Если аргумент оператору, opArgument, является сам объект, после вашего первого шага, элемент данных указателя в аргументе оператора, opArgument.ptr, не связан с расположением памяти. *opArgument.ptr содержит непредсказуемые значения. Поэтому на втором шаге выполняется инициализация новой ячейки памяти с непредсказуемыми значениями.

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

Проверьте самоназначение в операторе присвоения копии класса. Только после тестирования выполните назначения в операторе присвоения копирования.

Примеры

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

class MyClass1 { };
class MyClass2 {
public:
    MyClass2() : p_(new MyClass1()) { }
    MyClass2(const MyClass2& f) : p_(new MyClass1(*f.p_)) { }
    ~MyClass2() {
        delete p_;
    }
    MyClass2& operator= (const MyClass2& f)
    {
        delete p_;
        p_ = new MyClass1(*f.p_);
        return *this;
    }
private:
    MyClass1* p_;
};

В этом примере оператор присвоения копирования в MyClass2 не проверяет самоназначение. Если параметр f является текущим объектом, после оператора delete p_, память, выделенная указателю f.p_ также освобождается. Поэтому заявление p_ = new MyClass1(*f.p_) инициализирует расположение памяти, p_ указывает на с непредсказуемыми значениями.

Коррекция - тест на самостоятельное присвоение

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

class MyClass1 { };
class MyClass2 {
public:
    MyClass2() : p_(new MyClass1()) { }
    MyClass2(const MyClass2& f) : p_(new MyClass1(*f.p_)) { }
    ~MyClass2() {
        delete p_;
    }
    MyClass2& operator= (const MyClass2& f)
    {
        if(&f != this) {
           delete p_;
           p_ = new MyClass1(*f.p_);
        }
        return *this;
    }
private:
    MyClass1* p_;
};

Информация о результатах

Группа: Объектно-ориентированная
Язык: C++
По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода
Синтаксис командной строки: MISSING_SELF_ASSIGN_TEST
Воздействие: среднее
Представлен в R2015b