Poza wszystkimi powszechnymi dyskusjami na temat tego, kiedy i jak przekazywać przez możliwie stałe odniesienie dla typów niepochodzących, tablice są tutaj wyjątkowe.
Ze względu na kompatybilność wsteczną z C, a to z powodu konkretnego problemu: tablice mogą być ogromne, tablice nigdy nie są naprawdę przekazywane wartością C ani C++. Tablica będzie rozpad na wskaźnik do pierwszego elementu, więc kiedy piszesz:
void foo(type array[100]);
Kompilator jest faktycznie przetwarzania:
void foo(type *array);
Niezależnie od wielkości tablicy jest (dwa typowe pułapki: ufając, że array
jest tablicą wewnątrz foo
i wierzy, że będzie zagwarantowane, że będzie na niej 100 elementów:
Teraz, w C++, można w rzeczywistości przekazywać tablice według referenc e, ale odniesienia musi być konkretnym typem tablicy, która zawiera rozmiar:
void foo_array(type (&array)[100]);
Składnia śmieszne nie jest informacją kompilator, że funkcja będzie miała tablicę dokładnie 100 elementów typu type
. Zaletą jest, że kompilator może wykonywać rozmiar sprawdzanie dla Ciebie:
// assuming 'type' is defined
int main() {
type array0[99];
type array1[100];
foo(array0); // compiles, but if size=100 is assumed it will probably break
// equivalent to: foo(&array0[0])
// foo2(array0); // will not compile, size is not 100
foo2(array1); // compiles, size is guaranteed to be 100
}
Teraz problemem jest to, że funkcja ta działa tylko dla tablicy dokładnie 100 elementów, aw niektórych przypadkach może chcesz wykonać ta sama operacja w różnych rozmiarach macierzy. Te dwa rozwiązania to: wzorowanie funkcji w rozmiarze tablicy, która zapewni bezpieczną dla rozmiaru implementację dla każdego używanego rozmiaru - większy czas kompilacji i rozmiar binarny, szablon jest kompilowany dla każdego innego rozmiaru - lub przy użyciu za pomocą składni wartości, która spowoduje, że tablica zaniknie - nie będzie bezpieczna pod względem wielkości, która musi zostać przekazana jako dodatkowy argument, mniejszy czas kompilacji i rozmiar binarny. Trzecią możliwością jest połączenie obu:
void foo(type *array, int size);
template <size_t N>
void foo(type (&array)[N]) {
foo(array, N);
}
W tym przypadku, gdy nie będzie jeden szablonie foo
dla każdego rozmiaru, kompilator najprawdopodobniej inline połączenia i wygenerowanego kodu, który jest równoważny do wywołującego zapewniając szereg i rozmiar. Bez dodatkowych obliczeń i bezpieczeństwa typu dla prawdziwych tablic.
Obecnie przekazywanie referencji jest bardzo rzadko używane w przypadku tablic.
Może twój nauczyciel oznaczało „przechodzą przez ** const ** reference powinno być używane tylko wtedy, gdy nie zamierzasz zmieniać żadnych danych wewnątrz funkcji. " – Dan
Nie, nie zrobił tego. Powiedział nam, że jest to reguła, aby używać wywołania referencyjnego, jeśli nic nie zmienisz. Widzę teraz z poniższych odpowiedzi, że nawet nauczyciele nie zawsze mają teraz to, o czym mówią. –
Masz rację. Nauczyciele nie zawsze wiedzą, o czym mówią. A czasami wiedzą, ale przypadkowo mylą. Czasami mówią, co trzeba, a uczniowie ich nie rozumieją. Nie wykluczaj ostatniej opcji. – jalf