Любые ошибки в копировании и операторе присваивания, имеющие немного другую семантику?

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

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!    
   }
   ...
};

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

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

 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);

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


person Alex Jenter    schedule 05.02.2010    source источник


Ответы (3)


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

person aem    schedule 05.02.2010
comment
Можно ли иметь публичный копировальный центр, но приватный op=? - person Alex Jenter; 05.02.2010
comment
@ Алекс: Да. Это означает, что если у вас есть полностью инициализированный Note, он не может быть назначен. Если ему нужны данные, он будет использовать метод copyDataFields. Его все еще можно сконструировать так, чтобы он соответствовал другой ноте: Note othernote(firstNote); - person GManNickG; 05.02.2010

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

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

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

person d3jones    schedule 05.02.2010

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

  1. Вы изменяете «естественную» семантику оператора присваивания, известную населению С++.

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

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

    Note n = notebook.getNote(id);
    

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

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

Note& Notebook::editNote(int id);
Note  Notebook::createNote(int id);
person mloskot    schedule 06.02.2010
comment
Я не хочу выставлять заметку для редактирования напрямую, я хочу копировать, редактировать, заменять исходное поведение. - person Alex Jenter; 06.02.2010
comment
Я с трудом понимаю, в чем разница между копированием, редактированием, заменой оригинала и получением оригинала, редактированием - person mloskot; 06.02.2010