Czy wektory są przekazywane do funkcji przez wartość lub przez odwołanie w C ++

97

Piszę w C ++. Jeśli mam jakąś funkcję void foo(vector<int> test)i wywołam ją w moim programie, czy wektor zostanie przekazany przez wartość lub odniesienie? Nie jestem pewien, ponieważ wiem, że wektory i tablice są podobne i że funkcja taka jak void bar(int test[])może przejść test przez odniesienie (wskaźnik?) Zamiast według wartości. Domyślam się, że musiałbym jawnie przekazać wektor przez wskaźnik / odniesienie, jeśli chciałbym uniknąć przekazywania wartości, ale nie jestem pewien.

Adam
źródło
5
C ++ ma semantykę „przekazywanie przez wartość”, więc jest przekazywana przez wartość. Możesz jednak zdecydować się na przekazanie przez odniesienie. Wybór naprawdę zależy od tego, co robi funkcja.
juanchopanza
2
użyj przez odniesienie, jeśli nie chcesz, aby funkcja zmieniała zawartość wektora, uczyń ją stałą, w przeciwnym razie po prostu przekaż ją przez odniesienie. Pozwoli to uniknąć niechcianej i kosztownej (czasami) kopii
Ali Kazmi
3
Ponadto odniesienie nie jest wskaźnikiem.
Paramagnetic Croissant
2
@AliKazmi Z wyjątkiem sytuacji, gdy chcesz mieć kopię w treści funkcji.
juanchopanza
To zależy od tego, co chcesz osiągnąć. Używanie jednego ze standardowych inteligentnych wskaźników jest czasami przydatne, na przykład jeśli chcesz przekazać własność, użyj unique_ptr. Ale zwykle przekazuję std :: vector przez odniesienie.
Erik Alapää

Odpowiedzi:

137

Gdybym miał zgadywać, powiedziałbym, że pochodzisz z języka Java. To jest C ++ i rzeczy są przekazywane przez wartość, chyba że określisz inaczej za pomocą &-operator (zwróć uwagę, że ten operator jest również używany jako operator „address-of”, ale w innym kontekście). To wszystko jest dobrze udokumentowane, ale i tak powtórzę:

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

Możesz także zdecydować się na przekazanie wskaźnika do wektora ( void foo(vector<int> *bar)), ale jeśli nie wiesz, co robisz i czujesz, że tak naprawdę jest do zrobienia, nie rób tego.

Poza tym wektory to nie to samo co tablice! Wewnętrznie wektor śledzi tablicę, w której zarządza pamięcią, ale tak samo postępuje wiele innych kontenerów STL. Nie możesz przekazać wektora do funkcji oczekującej wskaźnika lub tablicy lub odwrotnie (możesz uzyskać dostęp do (wskaźnika do) tablicy bazowej i użyć tego). Wektory to klasy oferujące wiele funkcji poprzez swoje funkcje składowe, podczas gdy wskaźniki i tablice są typami wbudowanymi. Ponadto wektory są przydzielane dynamicznie (co oznacza, że ​​rozmiar można określić i zmienić w czasie wykonywania), podczas gdy tablice w stylu C są przydzielane statycznie (ich rozmiar jest stały i musi być znany w czasie kompilacji), co ogranicza ich użycie.

Sugeruję, abyś przeczytał trochę więcej o C ++ w ogóle (szczególnie rozpad tablic ), a następnie rzucił okiem na następujący program, który ilustruje różnicę między tablicami a wskaźnikami:

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
źródło
2
Czy ktoś może mi pomóc zrozumieć ostatnią deklarację funkcji foo4? Dlaczego zwraca rozmiar tablicy zamiast rozmiaru wskaźnika, jak w innych funkcjach?
abhishek_M
3
@abhishek_M, ponieważ typ parametru to odwołanie. Odwołanie może być powiązane tylko z wyrażeniem dokładnie tego samego typu. Z tego powodu tablica nie ulega rozpadowi, ponieważ odwołanie do tablicy nie może być powiązane ze wskaźnikiem, może być powiązane tylko z tablicą tego samego typu (w tym przypadku tablica 10 liczb całkowitych)
bolov
1
c ++ 11 ma "semantykę przenoszenia" i można to zrobić ostrożnie i przekazać wartość (z semantyką przenoszenia) bez kopiowania. Oto link, który bardzo mi pomógł: mbevin.wordpress.com/2012/11/20/move-semantics
fchen
24

Funkcjonalnie A vectorjest taka sama jak tablica. Ale język vectorjest typem i intjest też typem. W przypadku argumentu funkcji tablica dowolnego typu (w tym vector[]) jest traktowana jako wskaźnik. A vector<int>to nie to samo co int[](dla kompilatora). vector<int>nie jest tablicą, nie jest odwołaniem i nie jest wskaźnikiem - jest przekazywana przez wartość, a zatem wywoła konstruktor kopiujący.

Więc musisz użyć vector<int>&(najlepiej with const, if function go nie modyfikuje), aby przekazać go jako referencję.

Ajay
źródło
Jaka jest składnia przekazywania „tablicy wektorów” przez odniesienie do funkcji?
ab123
void functionName (std :: vector <int> (& vc) [5]) {}
RIanGillis,
9

void foo(vector<int> test)

wektor zostanie przekazany przez wartość w this.

Masz więcej sposobów przekazywania wektorów w zależności od kontekstu: -

1) Przekaż przez referencję: - To pozwoli funkcji foo zmienić zawartość wektora. Bardziej wydajne niż przekazywanie wartości, ponieważ unika się kopiowania wektora.

2) Przekaż przez odniesienie do stałej: - Jest to wydajne i niezawodne, gdy nie chcesz, aby funkcja zmieniała zawartość wektora.

ravi
źródło
1

kiedy przekazujemy w funkcji wektor po wartości jako argument, po prostu tworzy kopię wektora i nie ma żadnego wpływu na wektor, który jest zdefiniowany w funkcji głównej, kiedy wywołujemy tę konkretną funkcję. podczas gdy gdy przekażemy wektor przez odniesienie, cokolwiek jest zapisane w tej konkretnej funkcji, każda akcja będzie wykonywana na wektorze, który jest zdefiniowany w funkcji głównej lub innej, kiedy wywołujemy tę konkretną funkcję.

Nishant Yadav
źródło