Передаются ли векторы функциям по значению или по ссылке в C ++

97

Я кодирую на C ++. Если у меня есть какая-то функция void foo(vector<int> test)и я вызываю ее в своей программе, будет ли вектор передан по значению или ссылке? Я не уверен, потому что знаю, что векторы и массивы похожи, и что функция вроде void bar(int test[])бы проходит тест по ссылке (указатель?), А не по значению. Я предполагаю, что мне нужно было бы явно передать вектор по указателю / ссылке, если бы я хотел избежать передачи по значению, но я не уверен.

Адам
источник
5
C ++ имеет семантику «передачи по значению», поэтому он передается по значению. Однако вы можете решить перейти по ссылке. Выбор действительно зависит от того, что делает функция.
juanchopanza
2
используйте по ссылке, если вы не хотите, чтобы функция изменяла содержимое вектора, сделайте его константным, в противном случае просто передайте его по ссылке. Это позволит избежать нежелательных и дорогостоящих (иногда) копий
Али Казми
3
Кроме того, ссылка не является указателем.
Парамагнитный круассан
2
@AliKazmi За исключением случаев, когда вам нужна копия в теле функции.
juanchopanza
Это зависит от того, чего вы хотите достичь. Иногда полезно использовать один из стандартных интеллектуальных указателей, например, если вы хотите передать право собственности, используйте unique_ptr. Но обычно я передаю std :: vector по ссылке.
Эрик Алапяя

Ответы:

136

Если бы мне пришлось угадывать, я бы сказал, что вы из Java. Это 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)), но если вы не знаете, что делаете, и не чувствуете, что это действительно правильный путь, не делайте этого.

Кроме того, векторы - это не то же самое, что массивы! Внутренне вектор отслеживает массив, управление памятью которого он обрабатывает за вас, как и многие другие контейнеры STL. Вы не можете передать вектор функции, ожидающей указатель или массив, или наоборот (вы можете получить доступ к (указателю) базового массива и использовать его). Векторы - это классы, предлагающие множество функциональных возможностей через свои функции-члены, тогда как указатели и массивы являются встроенными типами. Кроме того, векторы распределяются динамически (что означает, что размер может определяться и изменяться во время выполнения), тогда как массивы в стиле 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);
}
JorenHeit
источник
2
Может ли кто-нибудь помочь мне понять последнюю функцию объявления foo4? Почему он возвращает размер массива вместо размера указателя, как в других функциях?
abhishek_M
3
@abhishek_M, потому что тип параметра является ссылкой. Ссылка может быть привязана только к выражению того же типа. По этой причине массив не распадается, потому что ссылка на массив не может быть привязана к указателю, она может быть привязана только к массиву того же типа (в данном случае массив из 10 целых чисел)
bolov
1
С ++ 11 имеет «семантику перемещения», и вы можете делать это осторожно и передавать по значению (с семантикой перемещения) без копирования. Вот ссылка, которая мне очень помогла
fchen
24

vectorФункционально A аналогичен массиву. Но для языка vectorэто тип, а intтакже тип. Для аргумента функции массив любого типа (включая vector[]) рассматривается как указатель. A vector<int>- это не то же самое, что int[](для компилятора). vector<int>не является массивом, не ссылкой и не указателем - он передается по значению и, следовательно, вызывает конструктор копирования.

Итак, вы должны использовать vector<int>&(желательно с const, если функция не изменяет его), чтобы передать его в качестве ссылки.

Аджай
источник
Каков синтаксис передачи «массива векторов» по ​​ссылке на функцию?
ab123 09
void functionName (std :: vector <int> (& vc) [5]) {}
RIanGillis 07
9

void foo(vector<int> test)

вектор будет передан по значению в этом.

У вас есть больше способов передачи векторов в зависимости от контекста: -

1) Передача по ссылке: - Это позволит функции foo изменить содержимое вектора. Более эффективен, чем передача по значению, поскольку предотвращается копирование вектора.

2) Передача по константной ссылке: - Это эффективно и надежно, если вы не хотите, чтобы функция изменяла содержимое вектора.

рави
источник
1

когда мы передаем вектор по значению в функцию в качестве аргумента, он просто создает копию вектора, и никакого эффекта не происходит с вектором, который определен в основной функции, когда мы вызываем эту конкретную функцию. тогда как когда мы передаем вектор по ссылке все, что написано в этой конкретной функции, каждое действие будет выполняться с вектором, который определен в основной или другой функции, когда мы вызываем эту конкретную функцию.

Нишант Ядав
источник