如何解决c++中函数的引用参数必须是const的一个直观原因
我正在查看此代码:
A foo() {
cout << "foo" << endl;
A a;
return a;
}
void bar(const A& a) {
cout << "bar" << endl;
}
int main() {
A a;
bar(a);
bar(foo());
}
并试图理解为什么当我传递 const
一个临时对象时,C++ 语言如此着急让我将 A& a
放在 bar
前面,就像我在 {{ 中所做的那样1}}.
毕竟,如果可以访问临时对象,那为什么我还要更改它呢?
有时我会传递一个 lValue 并且 bar(foo());
会根据需要更改它,有时我会发送一个 rValue 而 bar()
会浪费一点资源来更改它,然后,临时对象将被删除。有什么大问题?一些浪费的时钟周期?我可以忍受这一点!对吗?
为什么有人应该关心我如何处理我的临时对象?他们很快就会被删除,他们的信仰不关任何人的事..
解决方法
答案是foo()
!
太容易忘记或混淆我何时传递 lValue 以及何时传递 main()
中的 rValue。
持有对真实对象的引用并对其进行更改(写入)是所需的功能!
持有对临时对象的引用并更改它 - 乍一看 - 无害!对?写入临时对象可能发生的最坏情况是什么?反正很快就会过去的..
这当然不是真的。
如果 C++ 允许我将非常量临时对象传递给 bar()
,那么我的责任就是始终确保我在需要传递 lValue 时不会错误地将临时对象传递给 bar()
!
这是难以检测的错误的来源。所以最好是把程序员从他自己身上救出来,而不是让他有写临时对象的能力,不是因为我们要保存临时对象,而是因为我们要在COMPILE TIME早期拯救程序员关于他传递的逻辑错误一个 rValue,当他真的想改变一个 lValue 时。
例如,考虑以下代码:
A foo() {
cout << "foo" << endl;
A a;
return a;
}
A& dim(A& a) {
return a;
}
void bar( A& a) {
cout << "bar" << endl;
}
int main() {
A a;
bar(dim(a));
}
这里我们不需要使用 const,因为 bar()
现在从 dim()
获取对 lValue 的引用。
人类如何跟踪他何时传递对 lValue 的引用,以及何时传递对 rValue 的引用?他不能。
如果 c++ 允许一个方法接受对 rValue 的引用,那么调试将成为一个真正的硬错误,并且不会使开发人员的任何使用受益。永远。
我相信到目前为止,如果您正在阅读本文,您希望能像我一样-我不希望 C++ 允许我写入临时对象!没用的!它会使我的生活复杂化,迫使我检查自己是否某个方法返回对 lValue 或 rValue 的引用。
这就是 const
在这里很重要的原因,它区分了同一函数的两个版本:一个可以改变对象,一个不能
看看这段代码:
class A {
public:
A() { cout << "A ctor" << endl; }
A(const A& o){ cout << "A cctor" << endl; }
~A() { cout << "A Dtor" << endl; }
};
A foo() {
cout << "foo" << endl;
A a;
return a;
}
A& dim(A& a) {
return a;
}
void bar( A& a) {
cout << "bar" << endl;
}
void bar(const A& a) {
cout << "const bar" << endl;
}
int main() {
A a;
bar(dim(a));
bar(foo());
}
这里我们有两个几乎相同的方法,它们都命名为 bar
并且都接收到 A 实例的引用。
唯一的区别是其中一个可以更改引用,而其中一个不能。
调用 bar(dim(a))
将调用 void bar( A& a)
bar(foo())
将调用 bar(const A& a)
所以最后一次:如果 C++ 允许我将 rValue 发送到可以更改该 rValue 的方法,并且如果我犯了使用此选项的错误 - 这肯定是一个逻辑错误!因为没有理由更改 rValue。
逻辑错误比编译错误更难调试。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。