This article helped me a lot.
请暂时忘记指针。把这个和一粒盐一起吃。
引用是对象。当您通过引用传递时,您传递的是 对象。
当你通过值传递时,你传递了一个对象的副本; 另一个对象。它可能有相同的状态,但它是一个不同的实例;一个克隆。
因此,如果您满足以下条件,则通过引用传递可能是有意义的:
- 需要修改函数内部的对象
- 不需要(或不想)修改 对象,但希望避免复制它只是为了将其传递给函数。这将是一个
const 参考。
如果您满足以下条件,则按值传递可能是有意义的:
- 想从一个相同的 双胞胎开始,不打扰原来的双胞胎
- 不关心复制对象的成本(例如,我不会通过引用传递
int除非我想修改它)。
这里,看看这段代码:
#include<iostream>
struct Foo {
Foo() { }
void describe() const {
std::cout<<"Foo at address "<<this<<std::endl;
}
};
void byvalue(Foo foo) {
std::cout<<"called byvalue"<<std::endl;
foo.describe();
}
void byreference(Foo& foo) {
std::cout<<"called byreference"<<std::endl;
foo.describe();
}
int main() {
Foo foo;
std::cout<<"Original Foo"<<std::endl;
foo.describe();
byreference(foo);
byvalue(foo);
}
然后像这样编译它:g++ example.cpp
运行它:./a.out
并检查输出(实际地址可能在您的计算机中有所不同,但要点仍然存在):
Original Foo
Foo at address 0x7fff65f77a0f
called byreference
Foo at address 0x7fff65f77a0f
called byvalue
Foo at address 0x7fff65f779f0
注意called byreference 地址与Original Foo 地址相同(两者都是0x7fff65f77a0f)。请注意called byvalue 地址的不同(它是0x7fff65f779f0)。
提高一个档次。修改代码如下:
#include<iostream>
#include<unistd.h> // for sleeping
struct Foo {
Foo() { }
Foo(const Foo&) {
sleep(10); // assume that building from a copy takes TEN seconds!
}
void describe() const {
std::cout<<"Foo at address "<<this<<std::endl;
}
};
void byvalue(Foo foo) {
std::cout<<"called byvalue"<<std::endl;
foo.describe();
}
void byreference(Foo& foo) {
std::cout<<"called byreference"<<std::endl;
foo.describe();
}
int main() {
Foo foo;
std::cout<<"Original Foo"<<std::endl;
foo.describe();
byreference(foo);
byvalue(foo);
}
以同样的方式编译它,并注意输出(cmets 不在输出中;为清楚起见包括在内):
Original Foo
Foo at address 0x7fff64d64a0e
called byreference
Foo at address 0x7fff64d64a0e # this point is reached "immediately"
called byvalue # this point is reached TEN SECONDS later
Foo at address 0x7fff64d64a0f
因此,该代码旨在夸大副本的成本:当您通过引用调用时,不会产生此成本。当你按值调用时,你必须等待十秒钟。
注意:我的代码是在 OS X 10.7.4 中使用 GCC 4.8.1 编译的。如果您在 Windows 中,您可能需要与 unitsd.h 不同的东西才能使 sleep 调用正常工作。
也许这会有所帮助。