在 C++ 中通过引用/值传递

Posted

技术标签:

【中文标题】在 C++ 中通过引用/值传递【英文标题】:Pass by Reference / Value in C++ 【发布时间】:2010-09-29 11:07:12 【问题描述】:

我想澄清按值和按引用之间的区别。

我画了一幅画

所以,对于按值传递,

使用不同的引用创建相同对象的副本,并为局部变量分配新的引用,因此指向新的副本

如何理解单词: " 如果函数修改了该值,修改也会出现 在值传递和引用传递的调用函数范围内 "

谢谢!

【问题讨论】:

见img363.imageshack.us/img363/7202/passbyvaluereferencehg1.jpg 【参考方案1】:

我认为不传达通过引用传递的含义会产生很多混乱。当有些人说按引用传递时,他们通常不是指参数本身,而是被引用的对象。其他人说通过引用传递意味着对象不能在被调用者中更改。示例:

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

【讨论】:

你能解释一下“引用参数直接绑定到参数表达式” 如果实参的类型不同或者不是形参的派生类,并且没有对形参类型的转换运算符,则实参表达式not 直接绑定到引用参数。 如果参数是右值(如示例中的整数文字 42)。您可以在标准中找到详细的定义 in "void f1(Object const& o); f1(Object());"为什么允许 impl 复制临时文件? Iraimbilanja,因为标准是这样说的(阅读 8.5.3p5)。允许实现创建副本,但没有必须这样做。事实上,当将右值(Object())传递给 Object 的复制构造函数时,它不能这样做,以防止无限递归(它需要再次复制:p)【参考方案2】:

传值时:

void func(Object o);

然后调用

func(a);

您将在堆栈上构造一个Object,并且在func 的实现中它将被o 引用。这可能仍然是一个浅拷贝(ao 的内部可能指向相同的数据),所以a 可能会被更改。但是,如果oa 的深层副本,则a 不会改变。

引用传递时:

void func2(Object& o);

然后调用

func2(a);

您只会提供一种新的方式来引用a。 “a”和“o”是同一个对象的两个名称。在func2 中更改o 将使调用者可以看到这些更改,调用者知道对象名称为“a”。

【讨论】:

【参考方案3】:

非常感谢大家的所有这些意见!

我从网上的讲义中引用了这句话: http://www.cs.cornell.edu/courses/cs213/2002fa/lectures/Lecture02/Lecture02.pdf

第一页第六张幻灯片

" 通过 VALUE 变量的值被传递给函数 如果函数修改了该值,则修改保留在 该功能的范围。

通过 REFERENCE 对变量的引用被传递给函数 如果函数修改了该值,修改也会出现 在调用函数的范围内。

"

再次感谢!

【讨论】:

作为 C++ 的初学者,尽管这篇文章是很久以前发布的,但我确实觉得这很有用。谢谢。【参考方案4】:

我不确定我是否正确理解了您的问题。这有点不清楚。但是,您可能会感到困惑的是:

    通过引用传递时,对同一对象的引用将传递给被调用的函数。对对象的任何更改都会反映在原始对象中,因此调用者会看到它。

    传值时,会调用拷贝构造函数。默认的复制构造函数只会进行浅拷贝,因此,如果被调用函数修改了对象中的整数,调用函数将不会看到,但如果函数更改了对象内指针指向的数据结构,那么由于浅拷贝,调用者会看到。

我可能误解了你的问题,但我想我还是会试一试。

【讨论】:

【参考方案5】:

当我解析它时,那些话是错误的。它应为“如果函数修改了该值,则在通过引用传递时,修改也会出现在调用函数的范围内,但在通过值传递时不会出现。”

【讨论】:

【参考方案6】:

我对“如果函数修改了该值,修改也出现在调用函数的范围内,通过值传递和引用传递”的理解是,它们是错误

在被调用函数中所做的修改在按值传递时在调用函数的范围内。

要么你打错了引用的词,要么它们是从任何上下文中提取出来的,导致出现错误,对吧。

您能否确保您正确引用了您的来源,如果没有错误,请在来源材料中提供更多围绕该声明的文字。

【讨论】:

以上是关于在 C++ 中通过引用/值传递的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中通过引用和值传递字符串

在 C++ 中通过引用传递类成员函数返回值

在python中通过引用传递引用

在 C# 中通过引用或值传递对象

有没有办法在函数调用中通过引用传递和通过值显式传递?

在 C++ 中通过引用传递对象