提问人:feelfree 提问时间:6/6/2013 最后编辑:Saurav Sahufeelfree 更新时间:11/30/2020 访问量:32270
为什么 C++ 复制构造函数必须使用 const 对象?
Why C++ copy constructor must use const object?
问:
我知道当我们定义类时,类的复制构造函数是必要的,因为三态法则。我还注意到复制构造函数的参数通常如以下代码所示: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,则要复制的对象在此过程中不会更改其内容。但是,我确实注意到有些人仍然使用第二种实现而不是第一种实现。是否有任何理由首选第二种实现?
答:
复制构造函数不应修改它从中复制的对象,这就是参数首选的原因。两者都有效,但首选,因为它明确指出传入的对象不应由函数修改。const
other
const
const
仅供用户使用。对于实际可执行文件,它不存在。
评论
mutable
任何类的使用者最不希望看到的是更改所复制对象的复制构造函数!因此,应始终标记为 const。
如果复制构造函数未将其参数指定为 const,则不会编译此片段。
const ABC foo;
ABC bar(foo);
评论
ABC bar(some_func_returning_ABC());
从逻辑上讲,修改您只想复制的对象应该是没有意义的,尽管有时它可能有某种意义,例如您想要存储该对象被复制的时间数的情况。但这可以与存储此信息的成员变量一起使用,甚至可以对 const 对象进行修改(第二点将证明这种方法的合理性)
mutable
您希望能够创建 const 对象的副本。但是,如果你没有用 const 限定符传递你的参数,那么你就不能创建 const 对象的副本......
您无法从临时引用创建副本,因为临时对象是右值,并且不能绑定到对非 const 的引用。如需更详细的解释,我建议阅读 Herb Sutter 关于此事的文章
评论
这里可能需要 const 的原因有两个:
- 它确保您在制作副本时不会意外“损坏”原件 - 这是一件好事,因为您真的不希望在复制原始对象时更改它!
- 您可以传入基本对象以外的其他内容 - 因为构造函数接受引用,如果它不是对象本身 - 例如表达式。
举例说明第二种情况:
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(ABC &other)
a+a
ABC(const ABC &other)
正如其他几个答案所指出的那样,修改其参数的复制构造函数将是一个令人不快的惊喜。然而,这并不是唯一的问题。复制构造函数有时与临时参数一起使用。(例如:从函数返回。而且对临时值的非常量引用不会飞,正如 SO 上其他地方所解释的那样。
从技术意义上讲,这不是“必须”。我们甚至在标准中也有这样的野兽,尽管它已被弃用。点击链接进行推理。
我们期望的复制语义是保持“模板”不变,并提供一个在所有方面都完全等价的克隆,你很难分辨出原始形式。
这是意料之中的,您应该三思而后行,以拥有一个不这样做的副本。它会让用户感到惊讶,并可能引入错误。还有沮丧和噪音,试着在谷歌上搜索“auto_ptr载体”只是为了看看计数。
问题的其余部分可能是“我发誓在实施中不触及原件,但想要不同的签名”。那么什么签名呢?让我们试试 T 和 T&。
T 退出,因为它需要 copy ctor 才能使用,而我们正在实现这一点。递归:参见递归。
这就剩下 T&.这实际上适用于很多案件。但是,如果你的原始对象碰巧以常量形式存在,或者是临时的,那就失败了。为什么要阻止这个不下雨的明智案例呢?
除了复制构造函数不应修改源实例的基本假设之外,本文还详细阐述了使用 const 的实际技术原因:
http://www.geeksforgeeks.org/copy-constructor-argument-const/
也就是说,我引用:
"...编译器创建的临时对象不能绑定到非常量 参考资料......”
评论
A
ABC B(A)
auto_ptr
const
const