复制ctor和赋值运算符中的任何陷阱都有略微不同的语义?

时间:2010-02-05 19:48:16

标签: c++ copy-constructor semantics assignment-operator

请查看以下代码并告诉我将来是否会导致问题,如果是,请如何避免这些问题。

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创建一个副本,编辑它,然后在管理Notes的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);

这种做法是否合理?如果没有,请指出可能的负面后果是什么!非常感谢!

3 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:4)

虽然这可能适用于您的具体情况,但我不会推荐它。

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

当您的代码没有按照您的想法执行操作时,很容易感到困惑。

答案 2 :(得分:1)

从技术上讲,它是可行的,技术上可行,但我不这样做。 我看到的问题是:

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

  2. 由于语义不同,两个双操作,复制构造和赋值不一致。

  3. 该解决方案容易出错,因为很容易意外调用复制构造函数,即使它看起来像是赋值。如果程序员以这种方式编写您的第二个用例:

    Note n = notebook.getNote(id);
    

    然后调用复制构造函数, not assignment ,因此您将n作为与预期不同的对象。

  4. 为什么不明确表达你的意图:

    Note& Notebook::editNote(int id);
    Note  Notebook::createNote(int id);