java C++:按值传递对象的原因
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10269355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++: Reasons for passing objects by value
提问by clstaudt
In Java, all variables containing proper objects are actually references (i.e. pointers). Therefore, method calls with these objects as arguments are always "by reference". Calling a method which modifies the state of the object also affects the original object (on the caller side).
在 Java 中,所有包含正确对象的变量实际上都是引用(即指针)。因此,使用这些对象作为参数的方法调用总是“通过引用”。调用修改对象状态的方法也会影响原始对象(在调用方)。
C++ is different: Here arguments can be passed by value or passed by reference. Calling a mutator method on an object which was passed by value leaves the original object unaffected. (I suppose call by value creates a local copy of the object).
C++ 不同:这里的参数可以按值传递或按引用传递。对按值传递的对象调用 mutator 方法不会影响原始对象。(我想按值调用会创建对象的本地副本)。
So my first response to this - coming from Java to C++ - is: ALWAYS use pointers when using objects as arguments. This gives me the behavior I have come to expect from Java.
所以我对此的第一个反应——从 Java 到 C++——是:在使用对象作为参数时始终使用指针。这给了我期望从 Java 中获得的行为。
However, one could also use "call by value" in case one does not need to modify the object in the method body. Are there reasons why one would want to do this?
但是,如果不需要修改方法体中的对象,也可以使用“按值调用”。有什么理由让人们想要这样做吗?
回答by Praetorian
ALWAYS use pointers when using objects as arguments
使用对象作为参数时总是使用指针
No, in C++ always pass by reference, unless your function can be called with nullptr
as a valid argument. If the function does not need to modify the argument, pass by const
reference.
不,在 C++ 中总是通过引用传递,除非您的函数可以nullptr
作为有效参数调用。如果函数不需要修改参数,则通过const
引用传递。
Passing arguments by value has several uses.
按值传递参数有多种用途。
If your function needs to create a copy of the argument it is better to create this copy by passing by value rather than creating a copy within the function. For instance:
如果您的函数需要创建参数的副本,最好通过按值传递来创建此副本,而不是在函数内创建副本。例如:
void foo( widget const& w )
{
widget temp( w );
// do something with temp
}
Instead use
而是使用
void foo( widget w ) // copy is made here
{
// operate on w itself
}
Doing this also has the benefit of allowing the compiler to movewidget
if possible, which is generally more efficient than creating copies.
这样做还具有允许编译器在可能的情况下移动的好处widget
,这通常比创建副本更有效。
回答by Luchian Grigore
You're wrong in that you should pass by pointer. If you want to pass by reference, well... simply pass by reference:
你错了,你应该通过指针传递。如果您想通过引用传递,那么...只需通过引用传递:
void foo(int& x)
{
x = 3;
}
int main()
{
int a = 0;
foo(a);
assert( a == 3 );
}
Also, note that passing by value guarantees that the your variable can't be changed inside the called context. Although so would passing by const
reference...
另请注意,按值传递可确保您的变量无法在被调用的上下文中更改。虽然通过const
引用传递也是如此......
回答by Adam Liss
If you pass objects to a function by value, that function is free to use those objects as "working" variables without affecting the caller.
如果按值将对象传递给函数,则该函数可以自由地将这些对象用作“工作”变量,而不会影响调用者。
回答by Ben Cottrell
in Java, a referenceis a garbage-collected "smart pointer".
在 Java 中,引用是垃圾收集的“智能指针”。
C++ also uses the concept of smart pointers, which are in the <memory>
library, called unique_ptr
and shared_ptr
. shared_ptr is reference-counted so can be used in the same way as Java References. unique_ptr is similar, except is noncopyable and a little more lightweight. The benefit of both is never ever needing to use the deletekeyword, and being able to rely on "pointers" which are protected by exceptions.
C++ 还使用了智能指针的概念,它在<memory>
库中称为unique_ptr
和shared_ptr
。shared_ptr 是引用计数的,因此可以像 Java 引用一样使用。unique_ptr 是类似的,除了不可复制且更轻巧。两者的好处是永远不需要使用delete关键字,并且能够依赖受异常保护的“指针”。
C++ also supports the concept of a reference- which is usually a good choice for passing objects around (And even better is reference-to-const). References in C++ are bound to the type of object which is passed, so you need to specify (using the reference symbol &
) in the function signature
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);
}
As for "raw" pointers - you can nearly always avoid them by using either a smart pointer, a reference, an iterator, or pass-by-value. plain ordinary pointers come with a mixed bag of "gotchas" which C++ inherited from the C language - if you've got a fairly recent compiler you should never really need to use them at all (unless you're going to be doing things like re-inventing the wheel for learning purposes with memory management, data structures, etc.)
至于“原始”指针——您几乎总是可以通过使用智能指针、引用、迭代器或按值传递来避免它们。普通的指针带有一大堆“陷阱”,C++ 继承自 C 语言——如果你有一个相当新的编译器,你根本不需要使用它们(除非你要做这样的事情)为学习目的重新发明轮子,包括内存管理、数据结构等)
回答by Jerry Coffin
You normally pass by value because something isa value and should act like a value. In many cases passing by const reference is close enough to the same to be worth considering. In other cases, it's not.
您通常通过值传递,因为某物是一个值并且应该像一个值一样运行。在许多情况下,通过 const 引用传递非常接近,值得考虑。在其他情况下,它不是。
Passing by value can also be an optimization. At least IMO, this more or less secondary, but it can be important anyway (especially in choosing between passing by const reference and passing a real value.
按值传递也可以是一种优化。至少 IMO,这或多或少是次要的,但无论如何它可能很重要(尤其是在通过 const 引用和传递实际值之间进行选择时。
IMO, the real question should be in the opposite direction: why should the compiler pass a reference when you've clearly told it to pass a value? The answer is "premature optimization". The designers of Java (to mention your example, though it's hardly unique in this) decided that they knew better than to let the compiler do what it was told. Since passing a large object by value canbe slow and mightbe a mistake, they decided to not let it happen at all, even though it can be fast and may well be exactly what was intended.
IMO,真正的问题应该是相反的方向:当你明确告诉编译器传递一个值时,为什么编译器还要传递引用?答案是“过早优化”。Java 的设计者(提到你的例子,虽然它在这方面并不是独一无二的)决定他们比让编译器做它被告知的更好。由于按值传递大对象可能很慢并且可能是错误的,因此他们决定根本不让它发生,即使它可以很快并且很可能正是预期的。
回答by EdChum
I think you should consider the variable types in your function signature as the contract to the caller. So if you declare you function as:
我认为您应该将函数签名中的变量类型视为调用者的契约。所以如果你声明你的功能是:
void foo( int a );
then you are saying i will copy your passed in value do whatever I like and it won't be modified.
那么你是说我会复制你传入的值做我喜欢的任何事情并且不会被修改。
If you declare like:
如果您声明如下:
void foo (int* a);
then I may modify what a
points to or indeed modify the pointer
然后我可以修改a
指向或确实修改指针的内容
so the semantic difference is that you are declaring what the contract of your function may do, with pointers and references (without const declared on the reference or the object that the pointer is pointing to) you may modify the variable.
所以语义上的区别在于,您正在声明函数的契约可以做什么,使用指针和引用(没有在引用或指针指向的对象上声明 const),您可以修改变量。
References are preferred in C++ as it is clearer what you are intending and you avoid the c style pointer to pointer function signatures that are necessary when passing pointers to functions where you want to modify what the pointer is pointing to, which leads to errors and head scratching before you realise what went wrong.
引用在 C++ 中是首选,因为它更清楚您的意图,并且您避免了指向指针函数签名的 c 风格指针,这是在将指针传递给您想要修改指针指向的函数时所必需的,这会导致错误和头在你意识到出了什么问题之前抓挠。
Pointers though still are very useful as paremeters, especially if you need to test if the pointer to the object is null or not, something that is not possible to do using references.
尽管指针作为参数仍然非常有用,尤其是当您需要测试指向对象的指针是否为空时,这是使用引用无法做到的。
回答by user997112
When passing by reference there is an inherit danger that you could inadvertently change the value passed to the method, inside the method. After the method call you could assume the method didn't change the object, when in fact it did.
当通过引用传递时,存在继承危险,您可能会在方法内部无意中更改传递给方法的值。在方法调用之后,您可以假设该方法没有改变对象,而实际上它确实改变了。
Passing by value has the negative aspect of extra memory required (and possibly a slight performance overhead) because you make a copy of the object you are passing in, but with the benefit that you can be sure your object passed into the method will not be modified inside the method.
按值传递具有需要额外内存的负面方面(可能还有轻微的性能开销),因为您制作了传入的对象的副本,但好处是您可以确保传递给方法的对象不会被方法内部修改。
回答by Aslan986
It's helpfull to avoid side-effects. If you program need such side-effect use call by reference.
这有助于避免副作用。如果您的程序需要这样的副作用,请使用按引用调用。