25

我明白,当我们定义一个类的时候,类的复制构造函数是必要的,因为三种状态的规则。我还注意到,复制构造函数的参数通常const如下代码所示:

class ABC {
public:
    int a;
    int b;
    ABC(const ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

我的问题是如果复制构造函数的参数不是 const 会发生什么:

class ABC
{
    public:
    int a;
    int b;
    ABC(ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

我知道在某些情况下,如果复制构造函数的参数是 const 那么第二个实现会失败。此外,如果复制构造函数的参数是 const,则要复制的对象在此过程中不会更改其内容。但是,我确实注意到有些人仍然使用第二个实现而不是第一个。是否有任何理由首选第二种实现?

4

8 回答 8

36
  • 从逻辑上讲,修改您只想复制的对象应该没有意义,尽管有时它可能有一些意义,例如您想要存储该对象被复制的次数的情况。但这可以与mutable存储此信息的成员变量一起使用,甚至可以针对 const 对象进行修改(第二点将证明这种方法的合理性)

  • 您希望能够创建 const 对象的副本。但是如果你没有使用 const 限定符传递你的参数,那么你就不能创建 const 对象的副本......

  • 您无法从临时引用创建副本,因为临时对象是右值,并且不能绑定到对非 const 的引用。对于更详细的解释,我建议Herb Sutter 关于此事的文章

于 2013-06-06T08:06:48.300 回答
13

您的类的任何消费者所期望的最后一件事是一个复制构造函数,它改变了被复制的对象!因此,您应该始终标记为 const。

于 2013-06-06T08:02:39.447 回答
12

这里可能需要 const 的原因有两个:

  1. 它确保您在制作副本时不会意外“损坏”原件 - 这是一件好事,因为您真的不希望在制作副本时更改原始对象!
  2. 您可以传入除基本对象以外的其他内容 - 因为构造函数需要引用,如果它本身不是对象 - 例如表达式。

以第二种情况为例:

 class ABC
    {
       public:
           int a;
           int b;
       ABC(const ABC &other)
       { 
         a = other.a;
         b = other.b;
       }
       ABC operator+(const ABC &other)
       {
           ABC res;
           res.a = a + other.a;
           res.b = b + other.b;
           return res;
       }
    }

  ...
  ABC A;
  a.a = 1;
  a.b = 2;
  ABC B(a+a);

如果构造函数是 ,则不会编译ABC(ABC &other),因为a+a它是 ABC 类型的临时对象。但如果是ABC(const ABC &other),我们可以使用计算的临时结果并仍然将其作为参考传递。

于 2013-06-06T08:08:28.073 回答
6

正如其他几个答案所指出的那样,修改其参数的复制构造函数将是一个令人不快的惊喜。然而,这不是唯一的问题。复制构造函数有时与临时参数一起使用。(示例:从函数返回。)并且对临时对象的非 const 引用不会飞,正如SO其他地方所解释的那样。

于 2013-06-06T08:08:46.853 回答
3

如果复制构造函数未将其参数指定为 const,则此片段将无法编译。

const ABC foo;
ABC bar(foo);
于 2013-06-06T08:03:49.680 回答
1

复制构造函数不应该修改它从中复制的对象,这就是参数const首选的原因other。两者都可以,但const首选是因为它明确指出传入的对象不应被函数修改。

const仅供用户使用。对于实际的可执行文件,它不存在。

于 2013-06-06T08:01:52.900 回答
1

除了复制构造函数不应该修改源实例的基本假设之外,本文还详细说明了使用const的实际技术原因:

http://www.geeksforgeeks.org/copy-constructor-argument-const/

即,我引用:

“......编译器创建的临时对象不能绑定到非常量引用......”

于 2017-11-05T00:48:20.720 回答
0

这不是技术意义上的“必须”。我们甚至在标准中也有这样的野兽,尽管它已被弃用。按照链接进行推理。

我们期望复制的语义是保持“模板”不变,并提供一个在所有方面都完全等效的克隆,你很难分辨出原始的形式。

可以预期,您应该三思而后行,以拥有一个不这样做的复制 ctor。它会让用户感到惊讶,并可能引入错误。以及沮丧和噪音,只需尝试在 Google 上搜索“auto_ptr 向量”即可查看计数。

问题的其余部分可能是“我发誓不会在实施中触及原件,但想要一个不同的签名”。那要什么签名呢?让我们试试 T 和 T&。

T 退出,因为它需要复制 ctor 才能使用,而我们正在实现这一点。递归:见递归

剩下的就是T&。这实际上适用于很多情况。但是,如果您的原始对象碰巧以 const 形式存在,或者是临时的,那就失败了。为什么要阻止根本不下雨的合理案例?

于 2013-06-06T10:28:43.607 回答