C++中对象是通过值传递还是引用传递给函数的?

5

我来自C#,在那里类实例是通过引用传递的(也就是说,调用函数时传递引用的副本,而不是值的副本)。我想知道在C++中如何实现。在下面的情况中,_poly = poly,它是将poly的值复制到_poly中,还是什么?

#include <vector>
using namespace std;

class polynomial {
    vector<int> _poly;
public:
    void Set(vector<int> poly);
};

void polynomial::Set(vector<int> poly) {
    _poly = poly;                             <----------------
}
8个回答

13

poly的值将被复制到_poly中,但这样做会多做一份副本。更好的方法是通过const引用传递:

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

编辑 我在评论中提到了拷贝并交换技术。另一种实现你所需的方式是

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

这样做的另一个好处是,你可以获得强异常保证,而不仅仅是基本保证。在某些情况下,代码可能会更快,但我认为这只是一个额外的奖励。唯一需要注意的是,由于存在隐式拷贝,此代码可能被称为“较难阅读”。


从异常安全的角度来看,你也可以使用复制并交换技术,但是作为一个初学者,那是一种高级技巧。 - rlbond
智能编译器将能够在对象未被修改时通过引用传递。 - Georg Schölly
3
@gs: 但为什么要依赖于那个呢?最好明确注明自己的调用语义。在调试模式下,无关紧要的复制仍然无法避免。 - rlbond
@gs: 真的吗?我不这么认为,要注意函数是否修改传递的对象,编译器必须看到函数的内部。现在,在编译其他编译单元时,只有签名存在,编译器无法知道内部函数对传递的元素做了什么。我不认为编译器可以执行该优化,您能提供一些指针吗? - David Rodríguez - dribeas
Copy-and-swap(void polynomial::Set(vector<int> poly) { _poly.swap(poly); })可以避免在上述版本中进行另一次复制,如果参数是临时的话。这通常是我编写代码的方式。 - Todd Gardner

4

这将浅复制int向量。通常情况下,它会像您预期的那样工作(_poly最终包含与poly相同的值)。

如果有指针(因为它们将按值复制),则可能会看到一些奇怪的行为。

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

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

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

可能值得一提的是,对于整数而言,浅拷贝和深拷贝是相同的。 - Rob Kennedy
浅拷贝和深拷贝在C++中并不是常用术语。 - anon
@Neil Butterworth,我认为浅拷贝/深拷贝是相当常用的——特别是在类具有指向对象的指针成员时,涉及到赋值运算符的情况下。 - Jesse Vogt

2
有三种可能性:

按值传递

void someFunction(SomeClass theObject);

传递指针

void someFunction(SomeClass *theObject);

按引用传递

void someFunction(SomeClass &theObject);

1
你应该提到指针/引用方法应该尽可能地使用const。对于那些刚接触C++的人来说,常常会忘记加上const,这样我们就无法保证输入值不会被改变了。 - DeusAduro

2

这将复制整个向量。在C++中,赋值是按值传递的。如果你正在分配一个指针,那么指针的值就被分配了。一旦初始化,引用可能不会被重新分配为指向另一个对象,因此对它们的赋值会改变所引用的对象。


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

1

您的向量将被复制。

实际上正在发生的是,向量的“=”运算符已被重载以执行实际复制操作。


0

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

在您的示例中,向Set()方法传递向量时会复制一次,再将其分配给_poly成员时会再次复制。

您可以通过引用传递向量来避免第一次复制:

void polynomial::Set(const vector<int>& poly) // passes the original parameter by reference
{
    _poly = poly; // still makes a copy
}

0

是的,你指向的那一行正在复制整个向量。此外,由于它不是const,函数调用时也会进行复制。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接