对C++来说是一个全新的概念。我看到人们通常在运算符重载中通过引用传递对象。嗯,我不知道什么时候真的有必要。在下面的代码中,如果我在对象c1的声明中删除"与",在运算符+中删除c2,我仍然会得到相同的结果。在这种情况下,当我们不想修改c1或c2时,是否有任何理由通过引用?
#include <iostream>
class Keys
{
private:
int m_nKeys;
public:
Keys(int nKeys) { m_nKeys = nKeys; }
friend Keys operator+(const Keys &c1, const Keys &c2);
int GetKeys() { return m_nKeys; }
};
Keys operator+(const Keys &c1, const Keys &c2)
{
return Keys(c1.m_nKeys + c2.m_nKeys);
}
int main()
{
Keys cKeys1(6);
Keys cKeys2(8);
Keys cKeysSum = cKeys1 + cKeys2;
std::cout << "There are " << cKeysSum.GetKeys() << " Keys." << std::endl;
system("PAUSE");
return 0;
}
运算符就像普通函数一样,只是有"花哨"的名称:)
(例如operator+()
而不是sum()
)
因此,应用于函数的参数传递规则也可以应用于重载运算符。
特别是,当您有一个不便宜的参数要复制时(例如,int
、float
是廉价复制参数的示例;std::vector
、std::string
是not廉价复制参数的实例),并且您在方法中观察此参数(即,它是输入只读参数),则可以通过常量引用(const &)
传递它。
通过这种方式,基本上就像原始参数的地址被传递给函数一样,所以不涉及深度复制。深度复制可能非常昂贵,例如,想象一个具有大量元素的向量。
因此,概括一下,当:时,您通过常量引用
- 参数只是不便宜复制(例如,对于int、float等,只是不用担心:传递值很好)
- 在函数/运算符实现中观察到参数(即,它是一个输入只读参数)
如果通过引用传递,则不会生成对象的副本,这对于更复杂的类可以极大地提高性能。
在这种情况下,性能成本可能是微不足道的,可以想象编译器可以完全优化它,但这仍然值得做。稍后,Keys类可能会变为更复杂的类。
通过引用的优点:
- 它允许我们让函数更改参数的值,这有时很有用
- 因为没有生成参数的副本,所以即使与大型结构或类一起使用,它也很快
- 我们可以通过const引用来避免无意的更改
- 我们可以从一个函数返回多个值
参考通过的缺点:
- 因为不能对文字或表达式进行非常量引用,所以引用参数必须是普通变量
- 很难判断通过引用传递的参数是输入、输出还是两者兼有
- 从函数调用中无法判断参数是否会更改。通过值传递的参数和通过引用传递的参数看起来是一样的。我们只能通过查看函数声明来判断参数是通过值传递还是通过引用传递。这可能导致程序员没有意识到函数会改变参数的值
- 由于引用通常由C++使用指针来实现,并且取消引用指针比直接访问指针慢,因此访问通过引用传递的值比访问通过值传递的值慢
您可以阅读以下内容:
http://www.cs.fsu.edu/~myers/c++/notes/references.html
考虑一个long
的vector
,其中有1000万个条目
void foo(vector<long> vl)
{
}
它将导致vector<long>
-的赋值运算符(或复制构造函数),并且需要复制所有10m元素。该临时对象(vl
)的后期析构函数将取消分配内存并执行其他清理操作。它肯定会影响的性能
有一些类,特别是在同步提供程序(关键部分等)周围,还有一些智能指针类,阻止复制构造函数和/或赋值运算符,这样就不会错误地创建赋值或对象。尽管可以实现移动构造函数或移动赋值运算符。