没有调用拷贝构造函数

10

考虑给定的代码

struct ABC
{
    ABC()
    {
        std::cout<<" Calling from default constructor";
    }

    ABC(const ABC &copy)
    {
        std::cout<<"Calling from copy constructor";
    }
};

int main()
{
    ABC abc = ABC();
}

我有两个问题


Q1) 从复制构造函数参数声明中删除const会导致错误。为什么?

Q2) 添加const关键字后,我没有看到对复制构造函数的调用。为什么?复制构造函数没有被调用,所以为什么还需要const?


TIA


我想补充第三个问题:为什么我们将那一行改为 ABC abc(ABC()); 后没有任何显示? - Kos
2
(Q3)的答案在这里。Q1和Q2的答案在这里 - Prasoon Saurav
@Prasoon:你发布的链接中没有回答Q1。 - Yakov Galka
@ybungalobill:问题1的答案是,C++中的临时对象无法绑定到非常量引用。如果没有const,代码将是不合法的。 - Prasoon Saurav
哦,请在发布之前搜索一下网站,这个问题已经被反复讨论过了... - Matthieu M.
4个回答

5
  1. 你需要使用const,因为你试图用一个const的临时ABC()初始化abc。如果构造函数不是const,编译器必须拒绝代码。

  2. 在你将其设为const后,代码符合标准,编译器可以编译。然而,在这种情况下,它允许优化掉复制操作,正如标准中所述,因此它会删除对复制构造函数的调用。


@ybungalobill:编译器并不总是在所有情况下生成复制构造函数,即使您没有明确编写与签名完全匹配的构造函数。我记不清规则了,但它们并不总是被生成。 - Puppy
2
你对默认的复制构造函数有误解:“如果类X的非模板构造函数的第一个参数是X&const X&volatile X&const volatile X&,并且没有其他参数或者所有其他参数都具有默认参数,则该构造函数是复制构造函数。” - UncleBens
2
如果代码能够编译通过,那么你可能正在使用VC++,它允许将临时对象绑定到非const引用作为一种非标准扩展。发现此代码错误的编译器在语言规范方面是正确的。 - UncleBens
@UncleBens:好的,但这是否意味着它防止创建具有const X&参数的默认复制构造函数? - Yakov Galka
2
临时的 ABC() 不是常量。它只是一个临时变量。这就回答了第一个问题。在 C++ 中,将非 const 引用绑定到临时变量是不合法的。 - AnT stands with Russia
显示剩余2条评论

3

Q1) 将复制构造函数参数声明中的const删除会导致错误。为什么?

ABC abc = ABC();

等同于

ABC abc((ABC()));

由于您正在将临时对象传递给复制构造函数,因此它只能绑定到const引用而不是非const引用。

复制构造函数可以接受非const引用(例如std :: auto_ptr ),但这意味着它们的使用更受限制。

Q2)添加const关键字后,我没有看到对复制构造函数的调用。为什么?复制构造函数没有被调用,那么为什么需要const?

在给定的情况下,编译器允许优化掉冗余的构造函数调用。如果它只能调用默认构造函数,为什么要创建一个默认对象再复制它呢?

但是,即使调用复制构造函数被优化掉了,编译器也必须检查代码是否按原样有效-就像复制构造未被优化掉一样。


2

由于不允许将临时对象绑定到非const引用,因此const是必需的。即使编译器优化了复制构造函数,但这是在较后阶段才完成的。

C++ 0x标准通过添加右值引用来解决这个问题。这将允许您将const参数删除到非const...

ABC( ABC&& copy) 

尽管您仍需要常规的引用复制构造函数...

+1 表示赞同;我猜那就是所谓的“移动构造函数”? - Kos
@kos:通常是这样,但并不意味着它必须遵循移动语义(即将原始对象保留在默认构造状态),因此,如果您只想为临时对象使用复制语义,则这也很有效。 - diverscuba23

1

如果您还定义了赋值运算符,您会发现甚至连它也没有被调用:编译器优化了ABC abc = ABC();ABC abc;,因为它们具有相同的语义。

关于另一个疑问,G++不会抱怨将复制构造函数参数声明为非const(即使使用-Wall -W -std=c++98也不会)。无论如何,我没有查看过标准。


你忘了加上 --pedantic,但这并没有改变什么。但这也不奇怪——为什么不允许在某些情况下只为非 const 对象拥有一个复制构造函数呢?或者为 const 和非 const 分别提供不同的复制构造函数呢? - Kos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接