C++ 为什么C++复制构造函数必须使用const对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16956693/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:47:17  来源:igfitidea点击:

Why C++ copy constructor must use const object?

c++copy-constructor

提问by feelfree

I understand that when we define a class copy constructor of the class is necessary as Rule of threestates. I also notice that the argument of the copy constructor is usually constas the following codes illustrate:

我知道当我们定义类的类复制构造函数时,作为规则是必要的。我还注意到复制构造函数的参数通常const如下面的代码所示:

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

My question is what would happen if the argument of the copy constructor is not const:

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

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

I understand that in some cases if the argument of the copy constructor is const then the second implementation would fail. Also if the argument of the copy constructor is const then the object to be copied will not change its content during the process. However, I do notice that some people still use the second implementation rather than the first one. Are there any reasons that the second implementation is preferred?

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

回答by JBL

  • Logically, it should make no sense to modify an object of which you just want to make a copy, though sometimes it may have some sense, like a situation where you'd like to store the number of time this object has been copied. But this could work with a mutablemember variable that stores this information, and can be modified even for a const object (and the second point will justify this approach)

  • You would like to be able to create copy of const objects. But if you're not passing your argument with a const qualifier, then you can't create copies of const objects...

  • You couldn't create copies from temporary reference, because temporary objects are rvalue, and can't be bound to reference to non-const. For a more detailed explanation, I suggest Herb Sutter's article on the matter

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

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

  • 您不能从临时引用创建副本,因为临时对象是右值,并且不能绑定到对非常量的引用。更详细的解释,我建议看Herb Sutter 关于这个问题的文章

回答by Bathsheba

The last thing any consumer of your class would expect is a copy constructor that changed the object that was copied! Therefore, you should always mark as const.

您的类的任何使用者都期望的最后一件事是更改被复制对象的复制构造函数!因此,您应该始终标记为 const。

回答by Mats Petersson

There are two reasons that const may be needed here:

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

  1. It ensures that you don't accidentally "damage" the original when making the copy - this is a good thing, because you don't really want your original object to be changed when making a copy of it!
  2. You can pass in something other than a basic object - since the constructor takes a reference, if it's not an object itself - say for example an expression.
  1. 它确保您在制作副本时不会意外“损坏”原件 - 这是一件好事,因为您并不真的希望在制作副本时更改您的原始对象!
  2. 您可以传入基本对象以外的内容 - 因为构造函数接受一个引用,如果它不是一个对象本身 - 例如一个表达式。

To exemplify the second case:

以第二种情况为例:

 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);

This won't compile if the constructor is ABC(ABC &other), since a+ais a temporary object of type ABC. But if it's ABC(const ABC &other), we can use the temporary result of a calculation and still pass it in as a reference.

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

回答by Andrew Lazarus

As several other answers point out, a copy constructor that modified its argument would be an unpleasant surprise. That is not, however, the only problem. Copy constructors are sometimes used with arguments that are temporaries. (Example: return from function.) And non-const references to temporaries don't fly, as explained elsewhereon SO.

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

回答by Paul Mitchell

If the copy constructor doesn't specify it's parameter as const then this fragment would not compile.

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

const ABC foo;
ABC bar(foo);

回答by Serdalis

Copy constructors should not modify the object it is copying from which is why the constis preferred on the otherparameter. Both will work, but the constis preferred because it clearly states that the object passed in should not be modified by the function.

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

constis for the user only. It doesn't exist for the actual executable.

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

回答by Balog Pal

It's not a "must" in technical sense. We even have such beast right in the standard, though it got deprecated. Follow the links for the reasoning.

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

The semantics of copy we expect is to leave the "template" unchanged and provide a clone that is an exact equivalent in all regards, that you have hard time to tell form original.

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

That being expected you shall think twice to have a copy ctor that does otherwise. It will surprise users and likely introduce bugs. And frustration and noise, just try to google for 'vector of auto_ptr' just to see the count.

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

The remainder of the question could be "I swear not to touch the original in implementation, but want a different signature". What signature then? Let's try T and T&.

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

T drops out as it would require copy ctor to be usable and we're implementing just that. Recursion: see recursion.

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

That leaves T&. That would actually work for a deal of cases. But just fail if your original object happens to sit around in a const form, or be temporary. Why hinder that sensible case for no rain at all?

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

回答by infinite-loop

In addition to the fundamental assumption that copy constructors should not modify the source instance, this article elaborates on the actual technical reason for using const:

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

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

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

Namely that and I quote:

也就是说,我引用:

"... compiler created temporary objects cannot be bound to non-const references ..."

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