4

请看下面的代码,告诉我以后会不会出现问题,如果会,如何避免。

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

简而言之,我希望复制构造函数创建对象的精确副本,包括其(数据库)ID 字段。另一方面,当我分配时,我只想复制数据字段。但我有一些担忧,因为通常复制 ctor 和 operator= 具有相同的语义。

id 字段仅供 Note 及其朋友使用。对于所有其他客户端,赋值运算符确实创建了一个精确的副本。用例:当我想编辑笔记时,我使用 copy ctor 创建一个副本,对其进行编辑,然后在管理笔记的 Notebook 类上调用 save:

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

这种方法合理吗?如果不是,请指出可能的负面后果是什么!非常感谢!

4

3 回答 3

9

如果您想要的语义与赋值运算符的预期不匹配,请不要使用它。相反,通过声明私有来禁用它operator=并定义一个函数,其名称可以明确发生了什么,例如copyDataFields.

于 2010-02-05T19:52:34.087 回答
4

尽管这可能适用于您的特定情况,但我一般不推荐它。

诸如 STL 之类的库期望复制构造函数和赋值运算符“像他们应该做的那样”工作。如果您违反了 C++ 语义,那么您可能会发现对象的 STL 容器无法正常工作。STL 将在不同的情况下调用复制构造函数和赋值运算符,具体取决于容器。

当您的代码没有按照您的想法执行时,很容易完全混淆。

于 2010-02-05T21:05:49.697 回答
1

从技术上讲,它是可行的,并且在技术上会起作用,但我不会那样做。我看到的问题是:

  1. 您更改了 C++ 填充所知道的赋值运算符的“自然”语义。

  2. 复制构造和赋值这两个孪生操作由于语义不同而不一致。

  3. The solution is error prone because it's easy to accidentally call copy constructor even if it looks as assignment. If a programmer writes your second use case this way:

    Note n = notebook.getNote(id);
    

    Then copy constructor is called, not assignment, so you get n as different object than expected.

Why not to make your intentions just clear and explicit:

Note& Notebook::editNote(int id);
Note  Notebook::createNote(int id);
于 2010-02-06T03:14:01.633 回答