Есть какие-нибудь ошибки в копировании ctor и операторе присваивания, имеющие немного разную семантику?

StackOverflow https://stackoverflow.com/questions/2209935

Вопрос

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

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

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

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

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

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

    Note n = notebook.getNote(id);
    

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

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

Note& Notebook::editNote(int id);
Note  Notebook::createNote(int id);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top