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

2021-12-07 00:00:00 function c++

据我所知:当您按值传递时,该函数会生成传递参数的本地副本并使用它;当函数结束时,它超出范围.当您通过 const 引用传递时,该函数使用对无法修改的传递参数的引用.然而,我不明白为什么一个人会选择一个而不是另一个,除非在需要修改和返回参数的情况下.如果您有一个没有返回任何内容的 void 函数,为什么要选择一个?

From what I understand: when you pass by value, the function makes a local copy of the passed argument and uses that; when the function ends, it goes out of scope. When you pass by const reference, the function uses a reference to the passed argument that can't be modified. I don't understand, however, why one would choose one over the other, except in a situation where an argument needs to be modified and returned. If you had a void function where nothing is getting returned, why choose one over the other?

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

So basically passing by const reference avoids copying the object. So in what situations is copying the object good? I mean, why not just use const references all the time if it optimizes performance all the time?

推荐答案

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

There are two main considerations. One is the expense of copying the passed object and the second is the assumptions that the compiler can make when the object is a a local object.

例如在第一种形式中,在 f 的主体中,不能假设 ab 没有引用同一个对象;所以 a 的值必须在写入 b 后重新读取,以防万一.在第二种形式中,a 不能通过写入 b 来改变,因为它是函数的局部变量,所以这些重新读取是不必要的.

E.g. In the first form, in the body of f it cannot be assumed that a and b don't reference the same object; so the value of a must be re-read after any write to b, just in case. In the second form, a cannot be changed via a write to b, as it is local to the function, so these re-reads are unnecessary.

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 修改的全局状态的一部分.

E.g.: In the first example, the compiler may be able to assume that the value of a local object doesn't change when an unrelated call is made. Without information about h, the compiler may not know whether an object that that function has a reference to (via a reference parameter) isn't changed by h. For example, that object might be part of a global state which is modified by 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
    // ...
}

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

Unfortunately, this example isn't cast iron. It is possible to write a class that, say, adds a pointer to itself to a global state object in its constructor, so that even a local object of class type might be altered by a global function call. Despite this, there are still potentially more opportunities for valid optimizations for local objects as they can't be aliased directly by references passed in, or other pre-existing objects.

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

Passing a parameter by const reference should be chosen where the semantics of references are actually required, or as a performance improvement only if the cost of potential aliasing would be outweighed by the expense of copying the parameter.

相关文章