可以采用许多不同的方式获取参数:
void foo(T obj);
void foo(const T obj);
void foo(T& obj);
void foo(const T& obj);
void foo(T&& obj);
void foo(const T&& obj);
我不包括通过指针获取参数,因为指针可能已经是T
类型。
前两种方式是按值获取对象,这将导致对象被复制(如果没有通过智能编译器进行优化)。
其他方法通过引用来获取对象(前两个通过l值引用,后两个作为r值引用),该对象应省略复制。合格的const
版本保证不会修改引用的对象。
如果我希望函数能够将各种值(变量,从函数返回的临时变量,文字等)作为参数,那么非对象修改版本(const
的原型应该是什么? )和可能修改对象的版本(不是const
)版本,如果我希望它是最有效的版本(避免调用复制构造函数,移动构造函数,赋值运算符,创建临时对象等)?
我不确定应该使用哪种类型的引用。如果这是一个主观的问题,我正在寻找每种方法的利弊。
答案 0 :(得分:6)
存在所有这些用于参数声明的组合的原因。这取决于您的需求:
void foo(T obj);
obj
被修改(因此已被复制)foo
可以修改 obj
[是副本] foo
未修改obj
,则相对于const T&
,这是 still 首选-假设 T
很小(适合1-2个CPU寄存器)void foo(const T obj);
obj
被修改(因此已被复制)foo
无法修改 obj
const
通常可以帮助您发现错误。这就是为什么通常将其用于避免意外修改obj
的原因。 (例如if (obj = 5)
)void foo(T& obj);
obj
foo
可以修改 obj
int
,double
等)来说,这可能会很慢,这意味着传递副本会更好。void foo(const T& obj);
obj
foo
无法修改 obj
void foo(T&& obj);
obj
会发生什么,并且如果以后没空,也没问题foo
可以通过将信息移到另一个地方来窃取数据来进行修改 obj
。void foo(const T&& obj);
foo
无法修改 obj
,这很少有用有很多特殊情况,所以这不是完整列表。
一些额外的位:
(const T& obj)
通常比仅仅(T obj)
更糟糕,原因有很多。但是请记住,呼叫者可以始终将T
设为std::reference_wrapper<const T>
以避免复制。不过,这可能会破坏功能。std::move
,也要进行很多操作-假设该类型具有必要的运算符。template <typename F> void execute(F f) { f(); }
最后,值得分享的是Bisqwit的this video制作的流程图,可以制作出精美的图形:
答案 1 :(得分:1)
在现代C ++中获取参数的最有效方法?
最有效的方式取决于参数的类型以及是否将修改参数。
对于适合处理器寄存器的类型,通过副本传递是最有效的。 (编译器可以选择将变量传递到寄存器中而不是堆栈中。)
对于较大的类型,包括参数将被修改的情况,通过引用传递是有效的(并且安全的)。通过指针传递是有效的,但不如通过引用传递安全。
对于许多参数,请考虑将其放入结构并将结构传递给函数(通过引用或const引用)。
使用适合寄存器内部的数据类型时,处理器效率最高。
注意:这是一个微优化,通常保留给时间紧迫的应用程序使用。在担心传递参数的效率之前,最好先进行鲁棒性和正确性研究。