Любые ошибки в копировании ctor и оператора присваивания имеют немного другую семантику? - PullRequest
4 голосов
/ 05 февраля 2010

Пожалуйста, посмотрите на следующий код и скажите мне, не вызовет ли он проблем в будущем, и если да, то как их избежать.

class Note
{
   int id;
   std::string text;

public:
   // ... some ctors here...

   Note(const Note& other) : id(other.id), text(other.text) {}

   void operator=(const Note& other) // returns void: no chaining wanted
   {
      if (&other == this) return;
      text = other.text;  
      // NB: id stays the same!    
   }
   ...
};

Короче говоря, я хочу, чтобы конструктор копирования создавал точную копию объекта, включая его поле идентификатора (базы данных). С другой стороны, когда я назначаю, я хочу просто скопировать поля данных. Но у меня есть некоторые опасения, поскольку обычно копия ctor и оператор = имеют одинаковую семантику.

Поле id используется только Note и его друзьями. Для всех остальных клиентов оператор присваивания создает точную копию. Вариант использования: Когда я хочу отредактировать заметку, я создаю копию, используя копию ctor, редактирую ее и затем вызываю save в классе Notebook, который управляет Notes:

 Note n(notebook.getNote(id));
 n = editNote(n); // pass by const ref (for the case edit is canceled)
 notebook.saveNote(n);

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

 Note n; 
 n = notebook.getNote(id); 
 n.setText("This is a copy");
 notebook.addNote(n);

Является ли этот подход правдоподобным? Если нет, пожалуйста, укажите возможные негативные последствия! Большое спасибо!

Ответы [ 3 ]

9 голосов
/ 05 февраля 2010

Если вам нужна семантика, которая не соответствует ожидаемой от оператора присваивания, не используйте ее. Вместо этого отключите его, объявив приватный operator= и определите функцию с именем, которое проясняет, что происходит, например copyDataFields.

4 голосов
/ 06 февраля 2010

Хотя это может работать для вашего конкретного случая, я бы не рекомендовал его вообще.

Библиотеки, такие как STL, ожидают, что конструктор копирования и оператор присваивания будут работать "так, как они должны". Если вы нарушите семантику C ++, вы можете обнаружить, что контейнеры STL ваших объектов не будут работать правильно. STL будет вызывать как ваш конструктор копирования, так и ваш оператор присваивания при различных обстоятельствах, в зависимости от контейнера.

Очень легко запутаться, когда ваш код не делает то, что вы думаете.

1 голос
/ 06 февраля 2010

Технически это выполнимо и технически будет работать, но я бы так не поступил. Проблемы, которые я вижу:

  1. Вы изменяете "естественную" семантику оператора присваивания, известную в C ++.

  2. Две операции-близнецы, конструкция копирования и присваивание, несовместимы из-за различной семантики.

  3. Решение подвержено ошибкам, поскольку легко вызвать конструктор копирования , даже если оно выглядит как присваивание. Если программист пишет ваш второй вариант использования так:

    Note n = notebook.getNote(id);
    

    Затем вызывается конструктор копирования, не присваивание , поэтому вы получаете n как объект, отличный от ожидаемого.

Почему бы не сделать ваши намерения просто ясными и ясными:

Note& Notebook::editNote(int id);
Note  Notebook::createNote(int id);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...