Quaisquer gotchas em cópia ctor e operador de atribuição tendo uma semântica ligeiramente diferente?

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

Pergunta

Por favor, olhe o seguinte código e me diga se ele vai causar problemas no futuro, e se sim, como evitá-los.

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

Em suma, eu quero que o construtor de cópia para criar uma cópia exata de um objeto, incluindo a sua (banco de dados) campo ID. Por outro lado, quando eu ceder, eu quero apenas para copiar os campos de dados. Mas eu tenho algumas preocupações, já que geralmente o ctor cópia eo operador = têm mesma semântica.

O campo ID é usado apenas por nota e seus amigos. Para todos os outros clientes, o operador de atribuição cria uma cópia exata. O caso de uso: Quando eu quero editar uma nota, eu criar uma cópia usando a cópia ctor, editá-lo e, em seguida, chamar save na classe Notebook que administra Notas:

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

Quando, por outro lado eu quero criar uma nova nota com o mesmo conteúdo que uma nota existente, eu posso fazer isso:

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

É esta abordagem plausível? Se não, por favor apontar o que as possíveis consequências negativas são! Muito obrigado!

Foi útil?

Solução

Se você quiser semântica que não correspondem ao que é esperado do operador de atribuição, então não usá-lo. Em vez disso, desativá-lo, declarando uma operator= privado e definir uma função com um nome que deixa claro o que está acontecendo, como copyDataFields.

Outras dicas

Embora este trabalho poder para o seu caso específico, eu não recomendo em geral.

Bibliotecas, como a STL esperar que o construtor de cópia e operador de atribuição ao trabalho "como eles deveriam". Se você violar o C ++ semântica, então você pode achar que os recipientes de STL de seus objetos não vai funcionar direito. O STL irá chamar tanto o seu construtor de cópia e seu operador de atribuição, sob circunstâncias diferentes, dependendo do recipiente.

É muito fácil ficar totalmente confuso quando o código não faz o que você acha que ele faz.

Tecnicamente, é factível e tecnicamente vai funcionar, mas eu não faria isso dessa maneira. Os problemas que vejo são:

  1. Você muda "natural" semântica do operador de atribuição como é conhecido pela população C ++.

  2. Os dois operações individuais, construção e atribuição de cópia, são inconsistentes por causa da diferente semântica.

  3. A solução é propenso a erros, porque é fácil para chamar acidentalmente construtor de cópia mesmo que pareça como atribuição. Se um programador escreve o seu segundo caso de uso dessa maneira:

    Note n = notebook.getNote(id);
    

    Em seguida, copie construtor é chamado, não atribuição , de modo a obter n como objeto diferente do que o esperado.

Por que não fazer as suas intenções apenas clara e explícita:

Note& Notebook::editNote(int id);
Note  Notebook::createNote(int id);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top