C ++:按值传递对象的原因

时间:2012-04-22 15:40:34

标签: java c++ oop

在Java中,包含适当对象的所有变量实际上都是引用(即指针)。因此,使用这些对象作为参数的方法调用始终是“通过引用”。调用修改对象状态的方法也会影响原始对象(在调用者端)。

C ++是不同的:这里的参数可以通过值传递或通过引用传递。在通过值传递的对象上调用mutator方法会使原始对象不受影响。 (我想按值调用会创建对象的本地副本。)

所以我对此的第一反应 - 从Java到C ++ - 是:当使用对象作为参数时,总是使用指针。这让我得到了我对Java的期望。

但是,如果一个人不需要修改方法体中的对象,也可以使用“按值调用”。是否有理由想要这样做?

8 个答案:

答案 0 :(得分:12)

  

使用对象作为参数

时,总是使用指针

不,在C ++中总是通过引用传递,除非可以使用nullptr作为有效参数调用函数。如果函数不需要修改参数,请通过const引用。

按值传递参数有几种用途。

如果您的函数需要创建参数的副本,最好通过传递值而不是在函数内创建副本来创建此副本。例如:

void foo( widget const& w )
{
  widget temp( w );
  // do something with temp
}

改为使用

void foo( widget w )  // copy is made here
{
  // operate on w itself
}

如果可能的话,这样做的好处是允许编译器move widget,这通常比创建副本更有效。

答案 1 :(得分:9)

你错了,你应该通过指针传递。如果你想通过引用传递,那么......只需通过引用传递:

void foo(int& x)
{
   x = 3;
}

int main()
{
   int a = 0;
   foo(a);
   assert( a == 3 );
}

另请注意,按值传递可确保无法在调用的上下文中更改您的变量。虽然这样会通过const引用...

答案 2 :(得分:3)

如果按值将对象传递给函数,该函数可以自由地将这些对象用作“工作”变量,而不会影响调用者。

答案 3 :(得分:3)

在Java中,引用是垃圾收集的“智能指针”。

C ++还使用智能指针的概念,它位于<memory>库中,名为unique_ptrshared_ptr。 shared_ptr是引用计数的,因此可以与Java引用相同的方式使用。 unique_ptr是类似的,除了不可复制和更轻量级。两者的好处永远不需要使用 delete 关键字,并且能够依赖受异常保护的“指针”。

C ++还支持引用的概念 - 这通常是传递对象的好选择(甚至更好的是引用 - const )。 C ++中的引用绑定到传递的对象类型,因此您需要在函数签名中指定(使用引用符号&

#include <string>

void foo(std::string& bar)
{
    bar = "world";
}

void foo2(const std::string& bar)
{
    //passed by reference, but not modifyable.
}

int main()
{
    std::string str = "hello";
    foo(str);
    foo2(str);
}

对于“原始”指针 - 您几乎总是可以通过使用智能指针,引用,迭代器或传值来避免它们。简单的普通指针带有一堆混合的“陷阱”,C ++继承自C语言 - 如果你有一个相当新的编译器,你根本不应该真的需要使用它们(除非你将要做的事情像通过内存管理,数据结构等为学习目的重新发明轮子。)

答案 4 :(得分:3)

您通常会按值传递,因为 某个值并且应该像值一样。在许多情况下,通过const引用传递足够接近相同值得考虑。在其他情况下,它不是。

按值传递也可以是optimization。至少IMO,这或多或少是次要的,但无论如何它都很重要(特别是在通过const引用和传递实际值之间进行选择。

IMO,真正的问题应该是相反的方向:当你明确告诉它传递一个值时,为什么编译器会传递一个引用呢?答案是“过早优化”。 Java的设计者(提到你的例子,尽管它在这方面并不是唯一的)决定他们知道比让编译器按照它所说的那样做更好。由于按值传递一个大对象可能很慢而可能是一个错误,他们决定不让它发生,即使它可以很快,很可能是究竟是什么意思。

答案 5 :(得分:1)

我认为您应该将函数签名中的变量类型视为与调用者的契约。所以如果你声明你的功能:

void foo( int a );

然后你说我将复制你传入的值做任何我喜欢的事情,它不会被修改。

如果您声明如下:

void foo (int* a);

然后我可以修改a指向或确实修改指针

的内容

所以语义上的区别在于你声明你的函数的契约可以做什么,使用指针和引用(没有在引用上声明const或者指针指向的对象)你可以修改变量。

在C ++中,引用是首选,因为它更清楚你想要的是什么,你避免使用指针函数签名的c样式指针,这些指针在将指针传递给你想要修改指针所指向的函数时是必需的,这导致在你意识到出了什么问题之前,错误和头部刮伤。

指针仍然作为参数非常有用,特别是如果你需要测试指向对象的指针是否为空,这是使用引用无法做到的事情。

答案 6 :(得分:1)

当通过引用传递时,存在继承危险,您可能无意中更改了方法内传递给方法的值。在方法调用之后,你可以假设该方法没有改变对象,实际上它确实如此。

按值传递具有所需额外内存的负面影响(可能还有轻微的性能开销),因为您复制了传入的对象,但有一个好处是可以确保将对象传递给方法不会在方法内修改。

答案 7 :(得分:0)

避免副作用很有帮助。如果您的程序需要这样的副作用,请参考。

相关问题