如果我想使类不可复制,“operator =”返回类型是否重要?

时间:2011-12-26 08:36:11

标签: c++ operators operator-overloading

假设我有一个不支持成员复制的类,所以我不想保留编译器实现的复制构造函数和赋值运算符。我也不想实现这些,因为

  1. 这样做需要额外的努力,我不需要在我班级或
  2. 中进行这些操作
  3. 这些操作在我的班级中没有意义
  4. 所以我想禁止它们。为此I'll declare them private and provide no implementation

    class NonCopyable {
    private:
       NonCopyable( const NonCopyable& ); //not implemented anywhere
       void operator=( const NonCopyable& ); //not implemented anywhere
    };
    

    现在我可以为operator=()成员函数选择任何返回类型。我选择哪种返回类型是否重要?

5 个答案:

答案 0 :(得分:7)

不,返回类型无关紧要。

C ++标准不对您自己声明的复制分配特殊成员函数的返回类型强加任何要求。它只需要operator=()即可“接受”XX&const X&volatile X&const volatile X&类型的一个参数。 ††因此,void operator=( const NonCopyable& );仍然是一个复制赋值运算符(用户声明的运算符,具体而言)。

因为您实际上已经提供了自己的复制赋值运算符,所以它将抑制默认复制赋值运算符的生成。这将强制所有对NonCopyable的复制赋值运算符的调用解析为您的,导致任何使用复制赋值运算符的尝试都无法编译,因为它已声明为private

class Foo : NonCopyable
{
};

int main()
{
    Foo a;
    Foo b;
    // Compiler complains about `operator=(const NonCopyable&)`
    // not accessible or something like that.
    a = b;
}

由于我永远无法实际使用它,因此它并不完全是规范的复制赋值运算符。如果我尝试使用复制赋值运算符,则会导致编译器错误,这正是您想要的。


†当然,从风格上来说,如果复制赋值操作符实际上有所作为,那就很重要了。通常,您希望操作符的行为与内置操作符一样,因此当您实际执行赋值时,返回X&是很好的做法。

  

†† C ++标准:12.8复制类对象[class.copy]

     

9 用户声明的 copy 赋值运算符X::operator=是类X的非静态非模板成员函数,只有一个   类型XX&const X&volatile X&const volatile X&的参数。

答案 1 :(得分:2)

不,因为您永远不会在代码中调用此运算符。为了清晰和一致,我倾向于保留返回类型NonCopyable&amp ;.

答案 2 :(得分:1)

不,因为即使你定义了它的实现,你也可以从operator=返回任何内容。

答案 3 :(得分:1)

不,没关系,因为你从未实现过return语句。如果您尝试调用运算符,编译器将无法找到实现(使用任何 return类型,因此返回类型无关紧要。)

有趣的是,boost::noncopyable的复制赋值运算符被声明为返回const noncopyable&,但我想这只是惯例。

答案 4 :(得分:1)

这很重要:

  • void确保从类的实现中产生一小部分意外/错误调用(a = b = c / f(d = e))产生编译时错误而不是链接时错误,可以节省编译时间并且更容易理解(与许多开发人员触及的大型课程相关性最低,有些人之前的熟悉程度有限)。

  • void会为我敲响警钟(希望是大多数开发者),想知道你是否:

    • 想要删除默认生成的operator=
    • 对于额外打字只是懒惰,或者
    • operator=
    • 的普遍预期语义感到陌生/漠不关心
  
    
      

考虑到开放性问题,其他程序员不太可能出现并认为你只是没有提供实现并随意添加它(你可能觉得评论是充分的)。

    
  
  • 返回对类型的引用可以使整个函数签名更加即时可识别,或者通过视觉搜索过去复杂的类型来查找operator=可能会产生相反的效果 - 所有这些都在旁观者的眼睛(和头脑)中。 ...