Оператор копирования-назначения, когда назначает себя

Я читал одну из рекомендованных книг по С ++, в разделе, посвященном копированию, который он предлагает;

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

пример в книге; класс имеет один элемент данных ps а также ps is string *

C& operator=(const C &rhs)
{
auto newp = new string(*rhs.ps)
delete ps;
ps = newp;
return *this;
}

но наш инструктор предложил

C& operator=(const C &rhs)
{
if (this == &rhs)
return *this;

delete ps;
ps = new string(*rhs.ps)
return *this;
}

Есть ли проблемы с подходом инструкторов?

0

Решение

Подход вашего инструктора несовершенен. Если new string(*rhs.ps) терпит неудачу, это бросит исключение, и это уйдет ps с недопустимым значением (ps будет указатель на удаленную память).

Вы должны убедиться, что new успешно перед удалением старых данных:

C& operator=(const C &rhs)
{
auto new_ps = new string(*rhs.ps);
delete ps;
ps = new_ps;
return *this;
}

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

Помните, что если у вас есть пользовательский оператор назначения копирования, вам, вероятно, также понадобится пользовательский оператор назначения перемещения, конструктор копирования, конструктор перемещения и деструктор. (Увидеть Правило Пяти).

В целом, это все еще ущербный дизайн. ps должен быть просто stringили должен быть умный указатель, такой как value_ptr. Управление памятью вручную утомительно и подвержено ошибкам.

2

Другие решения

Существует проблема в том, что код не будет скомпилирован. Вместо

if (this == rhs.this)

должно быть

if (this == &rhs)

в противном случае нет проблем.

2

есть ли проблемы с этим подходом?

Проблема в том, что он не делает то, что говорит предложение, и в любом случае это должно быть

C& operator=( const C &rhs)
{
if ( this == &rhs)
return *this;

// ...
}

и, вероятно, конечная цель — написать что-то вроде этого:

C& operator=( C temp)
{
Swap( temp );
return *this;
}

увидеть копировать своп идиома и обратитесь к «Исключительный C ++» для получения дополнительной информации по этой теме.

2

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

C& operator=(const C &rhs)
{
if (this == &rhs)
return *this;

// For example:
delete[] m_arr;
m_len = rhs.m_len;
m_arr = new int[m_len];
for (int i=0; i<m_len; i++)
m_arr[i] = rhs.m_arr[i];
}
2

Простое решение: использование станд :: unique_ptr:

struct C {
std::unique_ptr<std::string
C& operator=(const C &rhs)
{
ps = new string(*rhs.ps)
return *this;
}
};
0

Нет. С этим подходом проблем нет.

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

-1
По вопросам рекламы [email protected]