【发布时间】:2014-07-05 00:14:46
【问题描述】:
我想澄清按值和按引用之间的区别。
我画了一幅画
所以,对于按值传递,
使用不同的引用创建相同对象的副本,并为局部变量分配新的引用,因此指向新的副本
如何理解单词: " 如果函数修改了该值,修改也会出现 在值传递和引用传递的调用函数范围内 "
谢谢!
【问题讨论】:
标签: c++ pass-by-reference pass-by-value
我想澄清按值和按引用之间的区别。
我画了一幅画
所以,对于按值传递,
使用不同的引用创建相同对象的副本,并为局部变量分配新的引用,因此指向新的副本
如何理解单词: " 如果函数修改了该值,修改也会出现 在值传递和引用传递的调用函数范围内 "
谢谢!
【问题讨论】:
标签: c++ pass-by-reference pass-by-value
我认为不传达通过引用传递的含义会产生很多混乱。当有些人说按引用传递时,他们通常不是指参数本身,而是被引用的对象。其他人说通过引用传递意味着对象不能在被调用者中更改。示例:
struct Object {
int i;
};
void sample(Object* o) { // 1
o->i++;
}
void sample(Object const& o) { // 2
// nothing useful here :)
}
void sample(Object & o) { // 3
o.i++;
}
void sample1(Object o) { // 4
o.i++;
}
int main() {
Object obj = { 10 };
Object const obj_c = { 10 };
sample(&obj); // calls 1
sample(obj) // calls 3
sample(obj_c); // calls 2
sample1(obj); // calls 4
}
有些人会声称 1 和 3 是通过引用传递,而 2 是通过值传递。另一组人说除了最后一个之外都是按引用传递,因为对象本身没有被复制。
我想在这里定义我声称是通过引用传递。可以在此处找到对其的一般概述:Difference between pass by reference and pass by value。第一个和最后一个是值传递,中间两个是引用传递:
sample(&obj);
// yields a `Object*`. Passes a *pointer* to the object by value.
// The caller can change the pointer (the parameter), but that
// won't change the temporary pointer created on the call side (the argument).
sample(obj)
// passes the object by *reference*. It denotes the object itself. The callee
// has got a reference parameter.
sample(obj_c);
// also passes *by reference*. the reference parameter references the
// same object like the argument expression.
sample1(obj);
// pass by value. The parameter object denotes a different object than the
// one passed in.
我投票支持以下定义:
当且仅当被调用函数的相应参数具有引用类型并且引用参数直接绑定到参数表达式(8.5.3 /4)。在所有其他情况下,我们都必须通过值传递。
也就是说下面是传值:
void f1(Object const& o);
f1(Object()); // 1
void f2(int const& i);
f2(42); // 2
void f3(Object o);
f3(Object()); // 3
Object o1; f3(o1); // 4
void f4(Object *o);
Object o1; f4(&o1); // 5
1 是按值传递,因为它不是直接绑定的。实现可以复制临时文件,然后将该临时文件绑定到引用。 2 是按值传递的,因为实现会初始化文字的临时值,然后绑定到引用。 3 是传值,因为参数没有引用类型。出于同样的原因,4 是按值传递的。 5 是按值传递,因为参数没有引用类型。以下情况通过引用传递(按8.5.3/4等规则):
void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1
void f2(Object const& op);
Object b; f2(b); // 2
struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference
【讨论】:
传值时:
void func(Object o);
然后调用
func(a);
您将在堆栈上构造一个Object,并且在func 的实现中,它将被o 引用。这可能仍然是一个浅拷贝(a 和o 的内部可能指向相同的数据),因此a 可能会被更改。但是,如果o 是a 的深层副本,则a 不会改变。
引用传递时:
void func2(Object& o);
然后调用
func2(a);
您只会提供一种引用a 的新方法。 “a”和“o”是同一个对象的两个名称。在func2 中更改o 将使调用者可以看到这些更改,调用者知道对象名称为“a”。
【讨论】:
非常感谢大家提供所有这些意见!
我从网上的讲义中引用了这句话: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf
第一页第六张幻灯片
" 通过 VALUE 变量的值被传递给函数 如果函数修改了该值,则修改保留在 该功能的范围。
通过 REFERENCE 对变量的引用被传递给函数 如果函数修改了该值,修改也会出现 在调用函数的范围内。
"
再次感谢!
【讨论】:
我不确定我是否正确理解了您的问题。这有点不清楚。但是,您可能会感到困惑的是:
通过引用传递时,对同一对象的引用将传递给被调用的函数。对对象的任何更改都会反映在原始对象中,因此调用者会看到它。
传值时,会调用拷贝构造函数。默认的复制构造函数只会做一个浅拷贝,因此,如果被调用的函数修改了对象中的一个整数,调用函数不会看到这一点,但是如果函数改变了对象内指针指向的数据结构,那么由于浅拷贝,调用者会看到。
我可能误解了你的问题,但我想我还是会试一试。
【讨论】:
当我解析它时,那些话是错误的。它应为“如果函数修改了该值,则在通过引用传递时,修改也会出现在调用函数的范围内,但在通过值传递时不会出现。”
【讨论】:
我对“如果函数修改了该值,则修改也会出现在调用函数的范围内,以通过值传递和通过引用传递”这句话的理解是,它们是错误。
在被调用函数中所做的修改不在按值传递时在调用函数的范围内。
要么你打错了引用的词,要么它们是从任何上下文中提取出来的,导致出现错误,对吧。
您能否确保您正确引用了您的来源,如果没有错误,请在来源材料中提供更多围绕该声明的文字。
【讨论】: