什么时候应该让课程不可复制?

时间:2014-01-18 22:09:22

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

根据Google style guidelines,“很少有类需要复制。大多数都不应该有复制构造函数或赋值运算符。”

他们建议您使类不可复制(即,不给它复制构造函数或赋值运算符),而是建议在大多数情况下通过引用或指针传递,或者使用无法隐式调用的clone()方法。

但是,我听到了一些反对这一点的论点:

  • 访问引用(通常)比访问值慢。
  • 在某些计算中,我可能希望保留原始对象,只返回已更改的对象。
  • 我可能想将计算的值存储为函数中的本地对象并返回它,如果我通过引用返回它,我就无法做到。
  • 如果某个类足够小,则按引用传递速度较慢。

遵循本指南有哪些正面/负面影响?是否有任何标准的“经验法则”使类不可复制?创建新类时我应该考虑什么?

1 个答案:

答案 0 :(得分:6)

我的建议有两个问题:

  1. 它不适用于现代C ++,忽略移动构造函数/赋值运算符,因此假定按值获取对象(以前会复制过)通常效率低下。

  2. 它并不信任程序员做正确的事情并适当地设计他们的代码。相反,它会限制程序员,直到他们被迫违反规则。

  3. 您的班级是否应该是可复制的,可移动的,两者都是,或者两者都不应该是基于班级本身使用的设计决定。例如,std::unique_ptr是一个只能移动的类的一个很好的例子,因为复制它会使其整个目的无效。在设计课程时,问问自己复制课程是否有意义。大多数时候答案都是肯定的。

    这个建议似乎是基于这样一种信念,即程序员默认按值传递对象,当对象足够复杂时,这可能很昂贵。这不再是真的。当需要对象的副本时,你应该默认按值传递对象,并且没有理由害怕这个 - 在很多情况下,将使用移动构造函数,这几乎总是一个恒定的时间操作。

    同样,选择如何传递对象是一种设计决策,应该受到许多因素的影响,例如:

    1. 我需要这份物品的副本吗?
    2. 我是否需要修改此对象?
    3. 对象的生命周期是什么?
    4. 对象是可选的吗?
    5. 这些问题应该与您编写的每种类型(参数,返回值,变量等)一起询问。您应该找到很多用于按价值传递对象的用途,这些用户不会因复制而导致性能下降。

      如果您遵循良好的C ++编程实践,您的副本构造函数将是无bug的,因此不应该成为一个问题。实际上,许多类只能使用默认的复制/移动构造函数。如果一个类拥有动态分配的资源并且您正确使用智能指针,那么实现复制构造函数通常就像从指针复制对象一样简单 - 没有多大的空间来容纳错误。

      当然,Google提供的建议适用于处理代码的人员,以确保整个代码库的一致性。没关系。但是,我并不建议盲目地将它全部用于现代C ++项目。