Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C+中是否更好+;按值传递还是按常量引用传递? < C++ >通过值还是通过常数引用传递更好?_C++_Variables_Pass By Reference_Constants_Pass By Value - Fatal编程技术网

在C+中是否更好+;按值传递还是按常量引用传递? < C++ >通过值还是通过常数引用传递更好?

在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函数)的类 这在移动语义出现之前尤其如此。原因很简单

我想知道哪种练习更好。我意识到通过常量引用传递应该在程序中提供更好的性能,因为您没有复制变量

听起来你已经找到答案了。传递值很昂贵,但如果需要,可以提供一个副本供您使用。

取决于类型。您增加了必须进行引用和取消引用的小开销。对于大小等于或小于使用默认复制ctor的指针的类型,按值传递可能会更快。

通常建议对所有类型使用按常量传递引用,但内置类型除外(
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"));