默认情况下,对象是按值传递还是按引用传递?

By default, are objects passed by value or by reference?

提问人:devoured elysium 提问时间:7/21/2009 最后编辑:Jan Schultkedevoured elysium 更新时间:9/27/2023 访问量:4307

问:

来自 C#,其中类实例通过引用传递(即,在调用函数时传递引用的副本,而不是值的副本),我想知道这在 C++ 中是如何工作的。

在以下情况下,是复制 to 的值,还是什么?_poly = polypoly_poly

#include <vector>

class polynomial {
    std::vector<int> _poly;
public:
    void Set(std::vector<int> poly) { poly_ = poly; }
};
C++ 按引用 传递值

评论


答:

2赞 Fred Larson 7/21/2009 #1

这将复制整个向量。赋值是按 C++ 中的值进行的。如果要分配指针,则会分配指针值。一旦初始化,引用就不能重新赋值以引用另一个对象,因此赋值引用会更改引用对象。

2赞 Soo Wei Tan 7/21/2009 #2

向量的复制运算符将复制向量的内容。

4赞 Jesse Vogt 7/21/2009 #3

这将对整数向量进行浅拷贝。这通常会像您预期的那样工作(_poly最终将包含与 poly 相同的值)。

如果你有指针,你会看到一些奇怪的行为(因为它们会被值复制)。

通常,您希望通过 const 引用传递该参数:

void polynomial::Set( const vector<int>& poly )

在这种情况下,通过常量引用传递不会影响结果,并且会更有效,因为它将消除传递到方法中的向量的不需要副本。

评论

0赞 Rob Kennedy 7/21/2009
可能值得一提的是,对于整数,浅拷贝和深拷贝是一回事。
0赞 7/21/2009
浅拷贝和深拷贝在C++中并不常用
0赞 Jesse Vogt 7/21/2009
@Neil Butterworth,我认为浅/深拷贝是非常常用的 - 特别是在赋值运算符的上下文中,当类具有指向对象的指针的成员时。
13赞 rlbond 7/21/2009 #4

poly的值将被复制到 -- 但您将在此过程中制作一个额外的副本。更好的方法是通过 const 引用:_poly

void polynomial::Set(const vector<int>& poly) {
    _poly = poly;                      
}

编辑我在关于复制和交换的评论中提到过。实现所需内容的另一种方法是

void polynomial::Set(vector<int> poly) { 
    _poly.swap(poly); 
}

这为您提供了额外的好处,即拥有强大的异常保证而不是基本保证。在某些情况下,代码也可能更快,但我认为这更像是一种奖励。唯一的问题是,这段代码可能被称为“更难阅读”,因为人们必须意识到有一个隐式副本。

评论

0赞 rlbond 7/21/2009
从例外安全的角度来看,您也可以使用复制和交换,但您是初学者,这是一种高级技术。
0赞 Georg Schölly 7/21/2009
如果对象未被修改,智能编译器将能够通过引用传递。
3赞 rlbond 7/21/2009
@gs:但为什么要依赖它呢?最好明确地注明一个人的呼叫的语义。而且,在调试模式下,不会避免虚假副本。
0赞 David Rodríguez - dribeas 7/21/2009
@gs:真的吗?我不这么认为,要注意函数是否修改传递的对象,编译器必须看到函数内部。现在,在编译其他编译单元时,只有签名存在,编译器无法知道内部函数对传递的元素做了什么。我不认为编译器可以执行这种优化,你能在这里提供一个指针吗?
0赞 Todd Gardner 7/21/2009
Copy-and-swap (void polynomial::Set(vector<int> poly) { _poly.swap(poly); }) 如果参数是临时的,则可以避免上述版本中的另一个副本。这通常是我写它的方式。
0赞 Michael Kohne 7/21/2009 #5

是的,您指向的线正在复制整个向量。此外,函数调用上也会有一个副本,因为这不是 const。

基本上,如果向量有任何大小,这是非常昂贵的。

0赞 LBushkin 7/21/2009 #6

除非您通过引用(使用 & 前缀)分配或传递参数,否则您将按值传递。对于类,这意味着对象的副本是使用为该类型提供的或隐式生成的(浅层)复制构造函数构造的。这可能很昂贵 - 而且通常是不可取的。

在示例中,向量被复制两次 - 一次是作为参数传递给 Set() 方法时,另一次是将其分配给_poly成员时。

您可以通过引用传递向量来避免第一个副本:

void polynomial::Set(const vector<int>& poly) // passes the original parameter by reference
{
    _poly = poly; // still makes a copy
}
2赞 Georg Schölly 7/21/2009 #7

有三种可能性:

按值传递

void someFunction(SomeClass theObject);

传递指针

void someFunction(SomeClass *theObject);

通过引用传递

void someFunction(SomeClass &theObject);

评论

1赞 DeusAduro 7/21/2009
您应该提到指针/ref 方法应尽可能为 const。对于刚接触 c++ 的人来说,省略 const 是很常见的,反过来,我们不能再保证输入保持不变。
1赞 thom 7/21/2009 #8

您的矢量将被复制。

实际情况是,vector 的“=”运算符已被重载以执行实际复制。