C++中,向函数传递的向量是按值还是按引用传递的?

136

我正在使用C++编程。如果我有一个函数void foo(vector<int> test)并在程序中调用它,那么这个向量会被按值传递还是按引用传递?我不确定,因为我知道向量和数组很相似,而像void bar(int test[])这样的函数会按引用(指针?)而不是按值传递test变量。我的猜测是,如果我想避免按值传递,则需要显式地通过指针/引用传递向量,但我不确定。


5
C++采用“按值传递”的语义,因此它是按值传递的。但你可以决定使用引用传递。选择取决于函数的实际需求。 - juanchopanza
2
如果您不希望函数更改向量内容,请使用引用传递const,否则只需通过引用传递即可。这将避免不必要和昂贵(有时)的复制。 - Ali Kazmi
3
同时,引用不等同于指针。 - The Paramagnetic Croissant
2
@AliKazmi,除非你希望在函数体中获得副本。 - juanchopanza
这取决于你想要实现什么。有时使用标准智能指针之一是很有用的,例如如果你想要传递所有权,则使用unique_ptr。但通常,我会通过引用传递std::vector。 - Erik Alapää
4个回答

187

在C++中,除非你使用&运算符指定,否则东西都是按值传递的(请注意,该运算符也用作“取地址”运算符,但在不同的上下文中)。这一点已经有充分的文档说明,但我仍然要再次强调:

void foo(vector<int> bar); // by value
void foo(vector<int> &bar); // by reference (non-const, so modifiable inside foo)
void foo(vector<int> const &bar); // by const-reference

你也可以选择传递指向 vector 的指针 (void foo(vector<int> *bar)),但除非你知道自己在做什么并且确定这是正确的方法,否则不要这样做。

另外,vector 和数组是不同的!内部,vector 跟踪一个数组,处理了其内存管理,但许多其他 STL 容器也有类似功能。你不能将 vector 传递给期望指针或数组的函数,反之亦然(但你可以获取底层数组的指针并使用它)。vector 是通过其成员函数提供很多功能的类,而指针和数组是内置类型。此外,vector 是动态分配的(这意味着大小可能在运行时确定和更改),而 C 风格的数组是静态分配的(其大小是固定的,必须在编译时知道),这限制了它们的使用。

我建议你先阅读一些关于 C++ 的一般知识(特别是关于数组衰减的知识),然后看以下程序,它说明了数组和指针之间的区别:

void foo1(int *arr) { cout << sizeof(arr) << '\n'; }
void foo2(int arr[]) { cout << sizeof(arr) << '\n'; }
void foo3(int arr[10]) { cout << sizeof(arr) << '\n'; }
void foo4(int (&arr)[10]) { cout << sizeof(arr) << '\n'; }

int main()
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    foo1(arr);
    foo2(arr);
    foo3(arr);
    foo4(arr);
}

2
有人能帮我理解最后一个声明 foo4 函数吗?为什么它返回数组的大小而不是像其他函数一样返回指针的大小? - abhishek_M
5
由于参数类型是引用,所以只能将引用绑定到完全相同类型的表达式上。因此,数组不会衰减,因为对数组的引用不能绑定到指针上,它只能绑定到相同类型的数组上(在这种情况下是一个包含10个整数的数组)。 - bolov
1
C++11有“移动语义”,您可以小心地使用它并通过值传递(使用移动语义)而不进行复制。这是一个对我很有帮助的链接:https://mbevin.wordpress.com/2012/11/20/move-semantics/ - fchen
1
从语言设计的角度来看,foo3行为背后的目的/思路是什么?在编译时已知数组大小的情况下,为什么需要进行衰减? - QuaternionsRock
1
@codosopher foo1foo2foo3是100%等价的。在这三个函数中,参数arr都是指针类型。在foo2foo3中声明看起来像数组以及"数组大小"的事实完全被忽略了。这是从C继承下来的怪癖。 - bolov
显示剩余10条评论

34
一个 vector 在功能上和一个数组相同。但是,对于语言来说,vector 是一种类型,而 int 也是一种类型。对于函数参数,任何类型的数组(包括 vector[])都被视为指针。vector<int>int[] 不同(对于编译器来说)。vector<int> 不是数组、引用或指针,它是按值传递的,因此会调用复制构造函数。

因此,您必须使用 vector<int>&(最好加上 const,如果函数不修改它)作为引用来传递它。


如何通过引用将“向量数组”传递给函数的语法是什么? - ab123
void functionName(std::vector<int> (&vc)[5]){} - RIanGillis

12

void foo(vector<int> test)

在这里,vector是按值传递的。

根据上下文,还有更多可以传递vector的方式:

1) 引用传递:这将允许函数foo更改vector的内容。与按值传递相比更有效率,因为避免了复制vector。

2) 常量引用传递:当您不希望函数更改向量的内容时,这既有效又可靠。


2
当我们将向量作为参数在函数中通过值传递时,它只是创建了向量的副本,并且在调用该特定函数时没有任何影响发生在主函数中定义的向量上。 而当我们通过引用传递向量时,在该特定函数中所写的任何操作都将在调用该特定函数时对在主函数或其他函数中定义的向量执行。"最初的回答"

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