它是好C++通过的价值或通过不断参考?

我想知道哪个更好的做法。我认识到,通常应参考提供更好的绩效的程序,因为你不是复制的变量。

有帮助吗?

解决方案

以前通常建议最佳做法 1 使用const ref传递所有类型,但内置类型除外( char int double 等),用于迭代器和函数对象(lambdas,派生自 std :: * _ function <的类/代码>)。

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

使用C ++ 11,我们获得了 移动语义 。简而言之,移动语义允许在某些情况下,可以“按值”传递对象而不复制它。特别是,当您传递的对象是 rvalue 时,就是这种情况。 / p>

本身,移动物体仍然至少与通过参考传递一样昂贵。但是,在许多情况下,函数会在内部复制一个对象 - 即它将占用参数的所有权 2

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

  1. 我们可以通过引用传递对象,然后在内部复制。
  2. 我们可以按值传递对象。
  3. “按值传递”仍然会导致复制对象,除非该对象是右值。在rvalue的情况下,可以移动对象,这样第二种情况突然不再“复制,然后移动”,而是“移动,然后(可能)再次移动”。

    对于实现正确移动构造函数的大型对象(例如向量,字符串......),第二种情况比第一种情况更有效。因此,如果函数获取参数的所有权,并且对象类型支持有效移动,建议使用pass by value。


    历史记录:

    实际上,任何现代编译器都应该能够确定何时传递值很昂贵,并且如果可能的话隐式转换调用以使用const ref。

    理论上。在实践中,编译器不能总是在不破坏函数的二进制接口的情况下改变它。在某些特殊情况下(当函数被内联时),如果编译器可以通过函数中的操作确定原始对象不会被更改,则实际上将省略该副本。

    但总的来说编译器无法确定这一点,并且C ++中移动语义的出现使得这种优化的相关性降低了。


    1 例如在Scott Meyers, Effective C ++

    2 对于构造函数来说尤其如此,它可以接受参数并将它们存储在内部以构成构造对象状态的一部分。

其他提示

编辑: 新的第由戴维*亚伯拉罕上cpp-下一步:

希望的速度?通过价值。


通过价值的结构那里的复制是廉价的具有另外的优点,编译器可能认为的对象不别(不同对象)。使用通过参照的编译器不能认定总是如此。简单的例子:

foo * f;

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

编译器可以优化成

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

因为它知道f和g不分享同一个位置。如果克是一个参考(foo&),编译器不能有假定。由于g。我可以再被别的f-我和已经有一个值为7。因此编译会必须重新取的新的价值的g。我从存储器。

对于较之实践的规则,这是一个很好的一套规则中找到的 移动构造 第(高度推荐的读取)。

  • 如果能打算改变的参数作为一种副作用,把它通过非常量参考。
  • 如果功能不会修改其参数和参数的基本类型,采取它的价值。
  • 否则采取的它的常量基准,除非在下列情况下
    • 如果功能将需要作出副本的常量基准,无论如何,把它的价值。

"原始"上述手段基本上是小数据的类型有几个字节长并不是多态性(迭代、功能的对象,等等)或者昂贵的副本。在该文件中,有一个其他规则。这个想法是,有时候一想到做一个复制(在情况下的说法不能修改),并且有时候其中一个不想要(在情况下的一种想要使用的参数本身的功能,如果参数是一个暂时无论如何,例如)。本文详细说明了如何可以做到的。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 */
}

但是,如果你的目的的参数是写东西的论点,然后通过它的非常量参考

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

取决于类型。您正在添加必须进行引用和取消引用的小额开销。对于大小等于或小于使用默认副本ctor的指针的类型,传递值可能会更快。

正如已经指出的那样,它取决于类型。对于内置数据类型,最好按值传递。即使是一些非常小的结构,例如一对整数,也可以通过传递值来表现得更好。

这是一个示例,假设您有一个整数值,并且您希望将其传递给另一个例程。如果该值已被优化以存储在寄存器中,那么如果要将其作为引用传递,则首先必须将其存储在内存中,然后将指向该内存的指针放在堆栈中以执行调用。如果它是通过值传递的,那么所需要的只是将寄存器压入堆栈。 (细节比给定不同的呼叫系统和CPU更复杂。)

如果你正在进行模板编程,你通常不得不总是通过const ref,因为你不知道传入的类型。传递一些不好的值的传递惩罚要比传递一个内置的惩罚更糟糕。 -in由const ref。

输入

听起来你得到了答案。通过价值传递是昂贵的,但如果您需要,可以给您一份副本。

这是我在设计非模板函数的界面时通常所做的工作:

  1. 如果函数不想修改参数,则传递值 复制的值很便宜(int,double,float,char,bool等等......请注意,std :: string,std :: vector和标准库中的其余容器都不是)

  2. 如果要复制的值很昂贵,那么传递const指针 不希望修改指向的值,NULL是函数处理的值。

  3. 如果复制值和函数的值很高,则通过非const指针传递 想要修改指向的值,NULL是函数处理的值。

  4. 当复制值很昂贵且函数不想修改引用的值时,通过const引用传递,如果使用指针,则NULL将不是有效值。

  5. 当复制值很昂贵时,通过非const引用传递,并且函数想要修改引用的值,如果使用指针,则NULL将不是有效值。

通过const引用的规则更好。 但是如果你需要在本地修改函数参数,最好使用值传递。 对于某些基本类型,性能通常与传递值和引用相同。实际上是指针在内部由指针表示,这就是为什么你可以期望,对于指针来说两个传递在性能方面是相同的,或者甚至通过值传递可以更快,因为不必要的解引用。

根据经验,非类类型的值和类的const引用。 如果一个类真的很小,那么传递值可能会更好,但差别很小。你真正想要避免的是通过价值传递一些巨大的类并将它全部重复 - 如果你传递一个std :: vector并且其中含有相当多的元素,这将产生巨大的差异。

传递小类型的值。

传递大型类型的const引用(大型的定义可能因机器而异)但是,在C ++ 11中,如果要使用数据,则传递值,因为您可以利用移动语义。例如:

class Person {
 public:
  Person(std::string name) : name_(std::move(name)) {}
 private:
  std::string name_;
};

现在调用代码会执行:

Person p(std::string("Albert"));

只创建一个对象并直接移动到类 Person 中的成员 name _ 。如果您通过const引用,则必须创建一个副本以将其放入 name _

简单的区别: - 在函数中我们有输入和输出参数,所以如果你的传递输入和输出参数是相同的,那么如果输入和输出参数不同则使用引用调用,那么最好使用按值调用。

示例 void amount(int account,int deposit,int total)

输入参数:账户,存款 输出参数:总计

输入和输出是不同的使用vaule呼叫

  1. void amount(int total,int deposit)
  2. 输入总存款 输出总数

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top