在C+中是否更好+;按值传递还是按常量引用传递? < C++ >通过值还是通过常数引用传递更好?
我想知道哪种练习更好。我意识到通过常量引用传递应该在程序中提供更好的性能,因为您没有复制变量 听起来你已经找到答案了。传递值很昂贵,但如果需要,可以提供一个副本供您使用。取决于类型。您增加了必须进行引用和取消引用的小开销。对于大小等于或小于使用默认复制ctor的指针的类型,按值传递可能会更快。通常建议对所有类型使用按常量传递引用,但内置类型除外(在C+中是否更好+;按值传递还是按常量引用传递? < C++ >通过值还是通过常数引用传递更好?,c++,variables,pass-by-reference,constants,pass-by-value,C++,Variables,Pass By Reference,Constants,Pass By Value,我想知道哪种练习更好。我意识到通过常量引用传递应该在程序中提供更好的性能,因为您没有复制变量 听起来你已经找到答案了。传递值很昂贵,但如果需要,可以提供一个副本供您使用。取决于类型。您增加了必须进行引用和取消引用的小开销。对于大小等于或小于使用默认复制ctor的指针的类型,按值传递可能会更快。通常建议对所有类型使用按常量传递引用,但内置类型除外(char,int,double,等等),对于迭代器和函数对象(lambdas,派生自std::*\u函数)的类 这在移动语义出现之前尤其如此。原因很简单
char
,int
,double
,等等),对于迭代器和函数对象(lambdas,派生自std::*\u函数
)的类
这在移动语义出现之前尤其如此。原因很简单:如果按值传递,则必须创建对象的副本,并且,除了非常小的对象之外,这总是比传递引用更昂贵
使用C++11,我们已经获得了一些成功。简而言之,移动语义允许在某些情况下,对象可以“按值”传递,而无需复制它。特别是,当您要传递的对象是
就其本身而言,移动对象的成本至少与通过引用传递一样高。然而,在许多情况下,函数无论如何都会在内部复制一个对象,也就是说,它将获得参数的所有权。2
在这些情况下,我们有以下(简化的)权衡:
历史笔记: 事实上,任何现代编译器都应该能够判断何时按值传递代价高昂,并尽可能隐式地将调用转换为使用const ref 理论上。在实践中,编译器不可能总是在不破坏函数的二进制接口的情况下改变这一点。在某些特殊情况下(当函数内联时),如果编译器能够确定原始对象不会通过函数中的操作进行更改,那么副本实际上将被省略 一般来说编译器不能确定这一点,而C++中的移动语义的出现使这种优化变得不那么相关。
P>1,在Scott Meyers中,有效的C+++
2对于对象构造函数来说,这一点尤其常见,它可以接受参数并在内部存储它们,作为构造对象状态的一部分。作为一条规则,通过常量引用传递更好。 但如果需要在本地修改函数参数,最好使用按值传递。
对于某些基本类型,按值传递和按引用传递的性能通常相同。实际上,引用在内部由指针表示,这就是为什么您可以预期,例如,对于指针,两种传递在性能方面是相同的,或者甚至通过值传递也会更快,因为不需要取消引用。正如已经指出的,这取决于类型。对于内置数据类型,最好按值传递。即使是一些非常小的结构,例如一对int,也可以通过传递值来实现更好的性能 下面是一个示例,假设您有一个整数值,并且希望将其传递给另一个例程。如果该值已优化为存储在寄存器中,那么如果要将其作为引用传递,则必须首先将其存储在内存中,然后将指向堆栈上该内存的指针存储在内存中以执行调用。如果按值传递,则只需将寄存器推送到堆栈上。(与不同的调用系统和CPU相比,细节要复杂一些)
如果您正在进行模板编程,通常会被迫始终通过const ref传递,因为您不知道传入的类型。按值传递错误内容的惩罚要比按const ref传递内置类型的惩罚严重得多。根据经验规则,非类类型的值和类的const reference。
如果一个类真的很小,那么按值传递可能会更好,但差别很小。您真正想要避免的是通过值传递某个巨大的类,并将其全部复制—如果您传递的是包含相当多元素的std::vector,这将产生巨大的差异。编辑:Dave Abrahams在cpp上的新文章下一篇:
对于复制成本较低的结构,传递值还有一个额外的优点,即编译器可能会假定对象没有别名(不是相同的对象)。使用“按引用传递”,编译器不能假定总是这样。简单的例子:
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值
关于更多实用的规则,这里有一组在文章中找到的好规则(强烈推荐阅读)
- 如果
my::string uppercase(my::string s) { /* change s and return it */ }
bool all_uppercase(my::string const& s) { /* check to see whether any character is uppercase */ }
bool try_parse(T text, my::string &out) { /* try to parse, write result into out */ }
class Person { public: Person(std::string name) : name_(std::move(name)) {} private: std::string name_; };
Person p(std::string("Albert"));