为什么赋值运算符的参数应该在C ++中通过引用传递?

时间:2013-10-29 07:20:35

标签: c++ assignment-operator copy-and-swap

我读了第5版C ++入门。我看到在使用复制和交换的赋值运算符中使用非引用参数时可以,但在其他赋值运算符中,我们总是使用引用参数并在销毁左手操作数之前复制右手操作数以确保如果将对象分配给自身,则赋值运算符可正常工作。为什么不在稍后将在函数体中复制的赋值运算符中使用非引用参数,以便我们不需要在函数体中复制右边的操作数?

2 个答案:

答案 0 :(得分:3)

复制赋值运算符通常应该按值(不是引用)取其参数,以便使用by-value参数作为副本进行复制和交换。

如果您没有(仅)进行复制和交换,那么您的复制赋值运算符应该通过引用获取其参数。至于为什么你不进行复制和交换:可能是因为该类型的某些特定优化。例如,考虑一个简单可复制类型的std::array(为了省去讨论异常安全的麻烦)。最有效的分配是直接复制字节:您不需要对象的临时副本,并且您当然不希望交换。因此,在实践中,您将通过引用获取参数,编写std::copy,并期望编译器以最佳方式执行此操作。

复制赋值操作符中的特殊外壳自我赋值有时可以在教科书中看到,即使使用了copy-and-swap,但在C ++ 03中通常是一个坏主意。虽然它优化了自我赋值的情况,但是by-reference参数会对从临时赋值的情况进行去优化。在C ++ 11中,它显然不那么糟糕,因为临时赋值的情况可以由移动赋值运算符而不是复制赋值运算符来处理。但它可能仍然没有必要。在实际代码中,自我分配是非常罕见的,因此甚至可以证明在常见情况下的指针比较比在极少数情况下的副本增加了更多运行时。

我还没有读过“C ++ Primer”的第5版,你选择不显示你所询问的代码,所以我不能评论它给出赋值操作符的具体情况(通过引用获取参数的复制作业或其他方式。

很抱歉,但总的来说,我认为从统计数据来看,你比这本书更困惑;-)你说:

  

...在使用复制和交换的赋值运算符中,但在其他赋值运算符

好的,所以“其他赋值运算符”是使用copy-and-swap的赋值运算符?

  

我们总是使用引用参数并在销毁之前复制右边的操作数   左手操作数

如果您复制右侧操作数,则 进行复制和交换。或者至少你非常接近它,因为我已经制作了一份副本,除了交换以外的任何东西都可以将副本放到左侧。无论哪种方式,如果函数做的第一件事是复制一个by-reference参数,那么它应该按值获取参数。

  

确保赋值运算符在将对象分配给自身时正常工作

如果确保自我赋值正确的技术是始终复制右侧操作数,那么您应该按值获取参数。不需要任何其他东西。但是,还有其他确保自我分配工作的技术。其中一个可能发生在您未显示的代码中。

答案 1 :(得分:0)

主要原因是效率。对于一个小类/结构,它可能无关紧要,但如果它是一个大的复杂类,那是另一回事。如果按值传递,则将调用可能较大且复杂的复制操作。这可能需要大量的内存分配。

真正的答案是有时无关紧要。通常它真的很重要,因此最好的方法是始终使用引用。