在Java中,包含适当对象的所有变量实际上都是引用(即指针)。因此,使用这些对象作为参数的方法调用始终是“通过引用”。调用修改对象状态的方法也会影响原始对象(在调用者端)。
C ++是不同的:这里的参数可以通过值传递或通过引用传递。在通过值传递的对象上调用mutator方法会使原始对象不受影响。 (我想按值调用会创建对象的本地副本。)
所以我对此的第一反应 - 从Java到C ++ - 是:当使用对象作为参数时,总是使用指针。这让我得到了我对Java的期望。
但是,如果一个人不需要修改方法体中的对象,也可以使用“按值调用”。是否有理由想要这样做?
答案 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_ptr
和shared_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)
避免副作用很有帮助。如果您的程序需要这样的副作用,请参考。