为什么传递const引用而不是值?

时间:2010-04-06 05:22:24

标签: c++ function

据我理解:当你通过值传递时,函数会生成传递参数的本地副本并使用它;当函数结束时,它超出范围。当您通过const引用时,该函数使用对无法修改的传递参数的引用。但是,我不明白为什么会选择一个而不是另一个,除非需要修改和返回参数。如果你有一个无效的函数,那么为什么选择一个呢?

编辑:所以基本上通过const引用传递避免复制对象。那么在什么情况下复制对象好呢?我的意思是,如果它始终优化性能,为什么不一直使用const引用呢?

8 个答案:

答案 0 :(得分:48)

有两个主要考虑因素。一个是复制传递对象的费用,第二个是当对象是本地对象时编译器可以做出的假设。

E.g。在第一种形式中,在f的正文中,不能假设ab不引用同一个对象;所以在写入a之后必须重新阅读b的值,以防万一。在第二种形式中,a不能通过写入b来更改,因为它是函数的本地,因此这些重新读取是不必要的。

void f(const Obj& a, Obj& b)
{
    // a and b could reference the same object
}

void f(Obj a, Obj& b)
{
    // a is local, b cannot be a reference to a
}

例如:在第一个示例中,编译器可以假设在进行不相关的调用时本地对象的值不会改变。如果没有关于h的信息,编译器可能无法知道该函数对(通过引用参数)引用的对象是否未被h更改。例如,该对象可能是由h修改的全局状态的一部分。

void g(const Obj& a)
{
    // ...
    h(); // the value of a might change
    // ...
}

void g(Obj a)
{
    // ...
    h(); // the value of a is unlikely to change
    // ...
}

不幸的是,这个例子不是铸铁。可以编写一个类,例如,在其构造函数中向自身添加指向全局状态对象的指针,这样即使是类型的本地对象也可能被全局函数调用更改。尽管如此,仍然有更多机会对本地对象进行有效优化,因为它们不能通过传入的引用或其他预先存在的对象直接别名。

应该在实际需要引用语义的地方选择通过const引用传递参数,或者仅在复制参数的费用超过潜在别名的成本时才选择性能改进。

答案 1 :(得分:22)

按值传递参数并因此复制它们可能很昂贵 - const引用避免了这个昂贵的步骤,同时仍然向调用者承诺不会更改对象。

通常基本类型(intdouble,...)通过值传递,而类类型通过const引用传递。

然而,exceptions可以为类类型传递值有用。

答案 2 :(得分:4)

在某些情况下,制作对象的副本可能会极大地影响性能。考虑一个函数,该参数将为std::vector<long>,并且您希望传递具有100万个元素的向量。在这种情况下,您将要使用const引用而不是传递值。在this SO question 中,您可以找到针对您问题的简单通则。

答案 3 :(得分:2)

有时,制作一个对象的副本可能很昂贵,因此传递const引用将避免必须制作该副本。否则,我会说你应该简单地按值传递,如果这是语义上的要求。

答案 4 :(得分:2)

按值传递参数会导致传递给函数的对象副本的开销。

也许对象不可复制,您的选择有限。

答案 5 :(得分:2)

由于您将获得性能优势。假设你有一个大对象(就字节大小而言)。现在,如果您通过值将此对象传递给函数,则需要为此创建不必要的副本,但是您可以通过将const引用传递给该对象本身而不创建副本来获得相同的效果。由于引用通常存储为引擎盖下的指针,因此传递引用的成本仅为sizeof(pointer)

答案 6 :(得分:2)

数组不能通过值传递,因此这是使用const指针的好时机。

答案 7 :(得分:1)

避免制作不必要的副本,从而提高效果。