可能重复:
如何将对象传递给C++中的函数?
在我的游戏中,我过度使用了数学向量和运算符重载.
class Vector
{
float x, y;
};
Run Code Online (Sandbox Code Playgroud)
这基本上都是关于我的Vector类(排除的方法).
我不是C++的专家,我已经看过并阅读过传递为const并通过引用传递.
那么,下面的代码示例中的性能差异在哪里?
Float RandomCalculation( Vector a, Vector b )
{
return a.x * b.x / b.x - a.x * RANDOM_CONSTANT;
}
// versus..
Float RandomCalculation( Vector& a, Vector& b )
{
return a.x * b.x / b.x - a.x * RANDOM_CONSTANT;
}
// versus..
Float RandomCalculation( const Vector& a, const Vector& b )
{
return a.x * b.x / b.x - a.x * RANDOM_CONSTANT;
}
Run Code Online (Sandbox Code Playgroud)
每个选项对编译器的优化过程有什么好处?
我何时何地都要特别小心?
tem*_*def 125
通过const
引用传递是传递对象的首选方法,作为传值的智能替代方法.当您通过const
引用传递时,您通过引用获取参数(避免制作它的任何副本),但不能对原始对象进行任何更改(就像您按值获取参数时所发生的那样).
如果你考虑这三个功能:
void VersionOne(Vector v);
void VersionTwo(Vector& v);
void VersionThree(const Vector& v);
Run Code Online (Sandbox Code Playgroud)
所有这些之间都有微妙的区别.例如,第一个函数将在传入a时调用复制构造函数,Vector
以便它具有自己的本地副本Vector
.如果您的复制构造函数需要一段时间才能运行或执行大量资源分配和释放,这可能会很慢,但您可以对参数进行任何更改,而不会有任何更改传播回调用方的风险.当参数被清理时,函数末尾也会有一个析构函数调用,如果这个代价太大,建议避免这种设置.也就是说,对于小物体,它可能是完全可以接受的.
此函数的第二个版本Vector
采用引用,这意味着该函数可以对其进行任何更改,Vector
并且更改将传播回调用方.每当你看到一个函数通过非const
引用接受一个参数时,就像这个VersionTwo
函数一样,你应该假设它将修改参数,因为如果它不进行任何修改,它将通过const
引用来获取.如果您需要更改,您很可能通过引用接受该值Vector
; 例如,通过旋转它,缩放它等.这里涉及的一个权衡是Vector
当它被传递到这个函数时不会被复制,因此你将避免调用复制构造函数和析构函数.这可能会对您的程序产生性能影响,但如果这是您的推理,您可能应该通过const
引用传递.需要注意的一点是,跟随引用非常类似于跟随指针(事实上,大多数引用实现只是将它们视为自动解引用指针),因此每次访问时都可能会遇到小的性能损失.数据通过参考.但是,只有剖析可以告诉您这是否是一个主要问题,除非您有特别的理由认为它有问题,否则我不会担心.
该函数的最终版本Vector
采用const
引用,与通过常规引用一样,避免了任何复制.但是,在Vector
使用const
引用时,禁止Vector
对函数内部进行任何更改,因此客户端可以假定Vector
不会对其进行修改.(是的,从技术上讲,如果编写得不好或有mutable
数据成员,它可能会被修改,但我们暂时忽略它.这是高层次的想法,这一点很重要).如果您希望能够在不复制函数的情况下检查函数中的值并且不进行变更,那么此选项将会很好.
传递引用和传递引用之间还有一个区别const
,那就是函数在rvalues上的行为.如果你有一个临时Vector
对象 - 要么通过写入显式创建它,要么Vector()
像写一样对它进行一些数学运算v1 + v2
- 那么就不能将那个临时对象传递Vector
给一个通过引用接受其参数的函数,因为引用只能绑定到左值.这个想法是,如果你有这样的功能:
void DoSomething(Vector& v) {
v.x = 0.0f;
}
Run Code Online (Sandbox Code Playgroud)
然后编写没有意义
DoSomething(v1 + v2);
Run Code Online (Sandbox Code Playgroud)
因为这将改变x
临时表达式的字段.为防止这种情况,编译器将拒绝编译此代码.
但是,C++会产生异常并允许您将rvalues传递给通过const
引用获取其参数的函数,因为直观地说,您不应该通过const
引用来修改对象.因此,此代码完全合法:
void DoSomething(const Vector& v) {
cout << v.x << endl;
}
DoSomething(v1 + v2);
Run Code Online (Sandbox Code Playgroud)
所以,总结一下 -
const
引用意味着类似的事情 - 您希望能够查看该值而无法对其进行修改.const
reference而不影响程序的正确性.但是,在参考的间接性与复制和破坏参数的成本之间存在性能折衷.const
应该使用pass-by- not - reference来表示"我想修改参数".const
引用获取其参数的函数.希望这可以帮助!
要复制传递给函数的对象吗?如果传递对象"Vector a"
和"Vector b"
值,则必须处理复制它们的开销.对于小型结构,开销可以忽略不计.
如果通过引用或指针传递对象,则不会产生此开销.但是,通过指针或引用传递可能允许修改对象:
const
对象名称前面的关键字用于保证您的函数不会修改通过引用或指针传递给函数的对象.这不仅会告诉其他程序员您的函数可以安全使用,而且编译器也会严格执行它.在const
将此关键字用于此目的时,该关键字对性能没有影响.
如果您有大型对象,请通过const reference
或传递它们const pointer
.如果要修改传递给函数的对象,请使用引用或指针.如果您的对象是一个小结构,您可以按值传递它.
归档时间: |
|
查看次数: |
54608 次 |
最近记录: |