c++构造函数参数传递应该是常量引用还是值?

Y616388166


本质上所有的函数参数都是传值,是内部怎么使用而已。比如参数是指针或引用,在参数栈中,它其实也是一个值,然后被按照指针或引用来操作——这也是数组作为参数传递被蜕化为指针的原因。所以,我们一般不用太在意是什么,需要怎样的参数就怎样传,编译器会有相应的优化。

原则上说,为了效率,传递的参数本身尺寸应该尽量小,指针或引用、常亮都是地址值,不要以值形式传大尺寸的结构即可,改为指针或引用形式。


TonyDeng


看你的需求,如果需要改值,传obj&,不需要改值,最好传 const obj&,这能省去一次构造和析构,次数多的话效率能提升不少


石头剪子没有布


一般来说,尽量使用常量引用的,因为引用不会再去拷贝一份参数,值传参是要多拷贝一份的。


辰辰少儿编程


简单变量?数组?还是指针?相关教材中一章的内容。


素食的猫


它过去通常被推荐为最佳做法。



1、到使用Const Ref的通行证所有类型,内建类型除外(, , ),用于迭代器和函数对象。(lambdas,派生自).


在…存在之前尤其如此。移动语义..原因很简单:如果通过值传递,则必须创建对象的副本,并且,除了非常小的对象外,这总是比传递引用更昂贵。


使用C+11,我们获得了移动语义..简而言之,Move语义允许,在某些情况下,可以“按值”传递对象,而无需复制它。尤其是,当要传递的对象是r值.


就其本身而言,移动对象至少仍然与通过引用传递一样昂贵。但是,在许多情况下,函数无论如何都会在内部复制一个对象-也就是说,它将所有权争论的焦点。


2、在这些情况下,我们有以下(简化)权衡:


1.我们可以通过引用传递对象,然后在内部复制。


2.我们可以通过值传递对象。


“按值传递”仍然会导致复制对象,除非该对象是rvalue。在rvalue的情况下,可以移动对象,因此第二个大小写突然不再是“复制,然后移动”,而是“移动,然后(可能)再次移动”。



对于实现适当移动构造函数的大型对象(例如向量、字符串…),第二种情况是大刀阔斧比第一个更有效率。因此,建议如果函数拥有参数的所有权,并且对象类型支持高效移动,则使用PASSBY值。


事实上,任何现代编译器都应该能够知道什么时候传递值是昂贵的,并且在可能的情况下隐式地转换调用来使用ConstRef。


理论上。实际上,编译器不能总是在不破坏函数的二进制接口的情况下更改它。在某些特殊情况下(当函数内联时),如果编译器能够发现原始对象不会通过函数中的操作被更改,那么副本实际上将被删除。


但是一般来说,编译器不能确定这一点,而C+中移动语义的出现使得这种优化变得不那么重要了。



想要速度吗?通过价值传递。


在复制成本较低的情况下,按值传递结构具有编译器可能假定对象不别名(不是相同对象)的额外优势。使用按引用传递的编译器不能总是这样认为。简单的例子:


foo * f;void bar(foo g) { g.i = 10; f->i = 2; g.i += 5;}


编译器可以将其优化为


g.i = 15;f->i = 2;


因为它知道f和g不具有相同的位置。如果g是一个引用(foo&),编译器就不可能这样认为。因为G.I可以由f->i别名,并且必须有7的值,所以编译器必须从内存中重新获取G.I的新值。


对于更实际的规则,下面是一组很好的规则移动构造器文章(强烈推荐阅读)。


如果函数打算将参数更改为副作用,则以非Const引用方式进行。如果函数不修改其参数,且参数是原语类型,则按值取其值。否则由Const引用,除非在下列情况下



如果函数无论如何都需要复制Const引用,则按值取它。


上面的“原语”基本上是指一些字节长且不是多态的小数据类型(迭代器、函数对象等.)或者复制起来很昂贵。在那篇论文中,还有另一条规则。其想法是,有时一个人想要复制(如果参数不能被修改),有时一个人不想(如果一个人想要在函数中使用参数本身,如果这个参数是临时的,例如)。论文详细说明了如何做到这一点。在C+1x中,这种技术可以在语言支持下本地使用。在此之前,我会遵守上述规定。


示例:要使字符串大写并返回大写版本,就应该始终按值传递:无论如何,都必须获取它的副本(不能直接更改Const引用)-因此更好地使调用方尽可能透明,并尽早将其复制,以便调用方尽可能优化-这篇文章中详细介绍了以下内容:


my::string uppercase(my::string s) { /* change s and return it */ }


但是,如果您不需要更改参数,请参考Const:


bool all_uppercase(my::string const& s) {


/* check to see whether any character is uppercase */}


但是,如果参数的目的是将某项写入参数,则通过非const引用传递它。


bool try_parse(T text, my::string &out) { /* try to parse, write result into out */}


分享到:


相關文章: