【问题标题】:Pass by value vs Pass by reference(difference in space allocation of memory between the two)按值传递与按引用传递(两者之间内存空间分配的差异)
【发布时间】:2013-08-05 16:35:45
【问题描述】:

在 C++ 中,我们使用按引用传递,我们引用从参数传递给函数参数的地址,这本质上是一个指针,对吗?因此,虽然它们本质上是相同的东西,别名和所有,但指针是否也需要内存空间?所以我们不应该在参数函数中让我们调用 B 指向所传递参数的内存位置让我们调用 A 反过来是我们值的内存位置(因为 A 传递了我们值的内存位置作为论据)?

在我们使用按值传递的 java 中,我们会复制我们传递的任何地址(例如对对象的引用)。

所以最后我并没有真正看到按值传递和按引用传递之间的区别。按值传递为原始传递的参数分配内存空间,指向该值并按引用传递的副本将我们值的内存位置作为参数传递给我们的参数(在内存中分配空间的指针)函数用于指向值。

【问题讨论】:

  • 你有什么问题?
  • 对于引用传递,我们函数中的参数是否需要内存分配。是指针对吗?那么这与传递值有什么不同呢?传递值也需要从值的内存地址的副本中分配内存?我的意思是对于按引用传递和按值传递都有两个指向该值的变量。
  • 在 Java 中,您通过值传递引用。在 C++ 中有更多的选择。您可以通过值或引用传递;您甚至可以通过值或引用传递指向对象(与引用不同)的指针。 Java 的引用更像是 C++ 指针。 C++ 引用与指针根本不同。

标签: java c++ memory pass-by-reference pass-by-value


【解决方案1】:

在我们使用按引用传递的 C++ 中,我们引用我们传递的任何地址的地址 从实参到函数的形参本质上是一个指针对吗?

没有。引用是现有变量的别名(即替代名称)。
但是在汇编级别,您的实现可能会将引用变量的地址放在地址寄存器(或类似的东西)中,以供被调用函数使用(如果这是您的意思的话)。

但为了简单起见,您可以将其视为自动取消引用的指针(这是我刚开始时所做的)。但是当你进入语言时,引用实际上与指针有根本的不同。

所以虽然它们本质上是一样的,别名和所有的东西,指针不是也需要内存空间吗?

C++ 级别的指针需要空间(因为它是可寻址的)。您可以获取指针的地址。从根本上说,引用不需要空间(因为您无法获取其地址)。在实现级别,它可能有也可能没有物理内存位置,具体取决于编译器如何实现它。

所以我们不应该在参数函数中调用 B 指向所传递参数的内存位置,让我们调用 A

如果您用代码示例解释了上述内容,那就太好了。但我想我明白了。假设函数没有内联,那么作为引用传递的任何参数都需要某种形式的链接回原始对象(因为引用总是从根本上引用活动对象)。那么它是怎么做的。编译器实现细节(所以你不应该关心)。但可能是堆栈上的一个指针,也可能只是地址寄存器中的一个地址。

这又是我们值的内存位置(因为 A 将我们的值的内存位置作为参数传递)?

也许或不。参考文献在语言级别没有物理位置。所以编译器可以用它玩很多漂亮的小技巧。

在我们使用按值传递的 java 中,我们会复制我们传递的任何地址(例如对对象的引用)。

在 Java 中,您通过值传递引用。但是 Java 引用基本上只是指向内存位置的指针。所以你通过值传递一个指针。这是使用的一种技术。幸运的是,C++ 不会将您限制在一种技术上。

您可以通过值或引用传递参数。您甚至可以通过值或引用传递指向对象的指针。因此,可以根据情况使用一些有趣的技术。

所以最后我并没有真正看到按值传递和按引用传递之间的区别。

可能是因为您正在考虑 java 引用(按值传递)。

在 C++ 中。如果您按值传递,您将创建一个作为参数传递的新对象(这意味着您制作原始对象的副本,这可能会花费)。如果通过引用传递,则将别名传递给对象。因此,当您与对象交互时,您正在修改原始对象。

 int inc(int val)     // pass by value
 {
     return ++val;    // increment the passed value and return as a result.
 }

 int incref(int& val) // pass by reference
 {
     return ++val;    // increment the reference.
                      // Since the reference is an alias this increment affects the
                      // original object. The result is returned.
 }

 void code()
 {
       int x = 5;
       int y = inc(x);  // x =5 and y = 6

       int a = 8;
       int b = incref(a); // a = 9 and b = 9
 }  

按值传递为原始传递的参数分配内存空间,指向该值并通过引用传递的副本将我们值的内存位置作为参数传递给参数(在内存中分配空间的指针) ) 在我们的函数中用于指向值。

对不起,我弄丢了。

【讨论】:

  • 我想我明白了。我的问题实际上应该更具体地通过值传递而不是通过引用传递对象。所以你说在 C++ 中,引用可能实际上有也可能没有物理内存空间,但如果它确实与对象的值传递有何不同?因为我们将对象的引用作为参数传递,这是我们对象的内存位置。如果它确实有物理内存空间,它将通过值传递复制并通过引用传递,这两者有何不同?它们都有两个指向对象的内存空间分配
  • @user2644819:您必须记住,reference 这个词在 C++ 和 Java 中的含义完全不同。在上面我显示值和引用的代码中,它与对象的类型没有区别。我本可以使用std::string 而不是int 并且含义没有改变。
  • 按值传递。意味着您制作对象的副本并将副本传递给函数。对对象的任何操作都只会影响本地副本。
  • 通过引用传递。意味着您将对象的替代名称传递给函数。对本地对象的任何操作都会影响原始对象(因为引用只是一个替代名称)。
  • 嗯,我不明白其中的区别。它们不是一个内存位置吗?如果是这样,在按值传递时它在一个变量中,而在按引用传递时,我们的参数指向我们的参数给出的内存位置。您说:“您将对象的替代名称传递给函数”它们在我们的内存中是否具有相同的地址?
【解决方案2】:

Honest-to-god pass-by-value 复制变量的值并将其传递给函数。这通常通过将值直接压入堆栈来完成。被调用函数无法修改原始值。

示例:

a = 5
double(a); <-- but this is pass-by-value
print a
end

function double(x) <-- x is a variable with a value of 5
    x = 2*x;
    print x;
    return x;

在上面的示例中,值 5 被传递给 double()。函数中的x变成10,打印出10。函数返回,并打印 5。由于 a 的值(不是它的地址)被传递给 double(),因此 double() 无法更改 a 的值。

如果我们传递了一个指向a 的指针(通过引用传递),那么更改a 的值不会有问题。

【讨论】:

    【解决方案3】:

    在按值传递中,地址中的值是在运行时计算和传递的。但是在通过引用传递时,没有确定任何值,只有一个地址被传递给你自己读取值并直接在内存位置进行更改的函数——而不是传递给你的值,就像通过值传递一样——这是非常低级别,可能会导致问题,因为如果一个或多个程序同时对内存位置执行操作,则可能会产生歧义。这就是 java 不支持指针的原因之一。

    在传递值时,内存位置中的数据不会在您的函数执行操作时更改。因为它正在对它的副本执行操作。像java中的多线程。

    【讨论】:

    • 我想我的问题应该是传递对象的值,在这种情况下,我们传递的是该对象的引用,它本质上是该对象的内存位置,并通过引用传递,这在我看来就像同样的事情,因为您还传递了一个内存地址。因此,如果我说的是真的,而我知道按值传递会复制我们传递的那个参数,即内存位置,那么是否有内存分配用于按引用传递?
    • 我想我的问题应该是传递对象的值,在这种情况下,我们传递的是该对象的引用,它本质上是该对象的内存位置,并通过引用传递,这在我看来就像同样的事情,因为您还传递了一个内存地址。因此,如果我说的是真的,而我知道按值传递会在我们传递的函数的参数中复制该参数,这是我们对象的内存位置,是否有内存分配用于按引用传递?它是指向内存位置的参数中的指针吗?已编辑
    • 按值传递和按引用传递在使用一些内存进行“传递”时是相同的。如果有一个变量 x = 10;如果它的地址是 100。按值传递将传递 10,按引用传递将传递 100。只是你知道传入的值是整数还是地址,然后相应地使用它。但在这两种情况下,一些数据都是存储在某处,函数正在读取它。
    猜你喜欢
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    相关资源
    最近更新 更多