Я читал одну из рекомендованных книг по С ++, в разделе, посвященном копированию, который он предлагает;
Для оператора присваивания очень важно правильно работать,
даже когда объект назначен самому себе. Хороший способ сделать это — скопировать
правый операнд перед уничтожением левого операнда.
пример в книге; класс имеет один элемент данных 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;
}
Есть ли проблемы с подходом инструкторов?
Подход вашего инструктора несовершенен. Если 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. Управление памятью вручную утомительно и подвержено ошибкам.
Существует проблема в том, что код не будет скомпилирован. Вместо
if (this == rhs.this)
должно быть
if (this == &rhs)
в противном случае нет проблем.
есть ли проблемы с этим подходом?
Проблема в том, что он не делает то, что говорит предложение, и в любом случае это должно быть
C& operator=( const C &rhs)
{
if ( this == &rhs)
return *this;
// ...
}
и, вероятно, конечная цель — написать что-то вроде этого:
C& operator=( C temp)
{
Swap( temp );
return *this;
}
увидеть копировать своп идиома и обратитесь к «Исключительный C ++» для получения дополнительной информации по этой теме.
Вы можете использовать следующую парадигму, чтобы избежать случая, когда вы сначала освобождаете ранее выделенные ресурсы, а затем перераспределяете их в соответствии с атрибутами входного аргумента (что в противном случае привело бы к нежелательному сценарию освобождения ресурсов входного аргумента):
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];
}
Простое решение: использование станд :: unique_ptr:
struct C {
std::unique_ptr<std::string
C& operator=(const C &rhs)
{
ps = new string(*rhs.ps)
return *this;
}
};
Нет. С этим подходом проблем нет.
Ну, теперь, когда вы отредактировали это, есть проблема. Если вам нужен хороший совет, я бы предложил дать людям полную информацию.