且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-11-12 08:45:22

有两个主要考虑。一个是复制传递的对象的代价,第二个是当对象是一个局部对象时编译器可以做出的假设。

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 的正文中,不能假定 a b 不引用同一个对象;因此,在写入 b 之后,必须重新读取 a 的值,以防万一。在第二种形式中, 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.