2017-01-04 12 views
9

Jaki jest sposób kanoniczny na uzyskanie odniesienia do podstawowej tablicy C (01)?Uzyskiwanie odniesienia do surowej tablicy ze std :: array

Metoda data() zwraca tylko nieprzetworzony wskaźnik, co czyni go nieodpowiednim, np. do przechodzenia w funkcje, które akceptują odniesienie do surowego układu o znanym rozmiarze.

Czy istnieje dobry powód, dla którego data() zwraca surowy wskaźnik, a nie odniesienie do podstawowej tablicy surowej, czy jest to tylko niedopatrzenie?

+5

Przekazywanie odniesień do rozmiarów tablic jest trudne i nie jest szeroko stosowane; dlaczego by tak było, skoro używałbyś tylko surowej tablicy do interakcji z kodem C, który i tak nie ma żadnych odniesień? – BoBTFish

+3

@WhiZTiM: OP oznacza, że ​​nie ma możliwości przekształcenia 'std :: array ' w coś, co można przekazać do 'myFunc (int (& k) [5])'. (Odniesienie do tablicy 5 int). –

+1

Cóż, być może dlatego, że komitet zaprojektował 'std :: array' jako doskonałą alternatywę. Niedopuszczenie, aby łatwo uzyskać odniesienie do podstawowej tablicy kolorów, może być po prostu przesuwaniem w kierunku, w którym chcą nas zaprogramować. – StoryTeller

Odpowiedz

13

Jaki jest kanoniczny sposób uzyskania macierzy bazowej surowego (C) tablicy (c) std :: tablica?

Nie ma sposobu na uzyskanie podstawowej tablicy C.

także, czy istnieje dobry powód, dla którego dane() zwraca wskaźnik surowy, a nie odniesienie do podstawowego surowca tablicy, czy jest to po prostu przeoczenie?

Wracamy: nie ma powodu, aby std::array zapewniała podstawową tablicę C. Jak już powiedziałeś, tablica C byłaby przydatna (przez surowy wskaźnik) tylko z funkcjami uzyskującymi odniesienie do tablic C.

Kiedy ostatni raz miałeś funkcję:

void foo(int (&arr)[5]) 

Me? Nigdy. Nigdy nie widziałem funkcję z parametrem odniesienia C tablicy z wyjątkiem coraz rozmiaru tablicy (i odrzucając odnośniki):

template <class T, std::size_t N> 
auto safe_array_size(T (&)[N]) { return N; } 

Niech nurkować trochę się dlaczego parametry odniesienia do tablic nie są używane.

Na początek, ze wskaźnika obszaru C z oddzielnym parametrem wielkości był jedyny sposób na przekazanie tablic, ze względu na rozpad tablicowy i brak typu referencyjnego.

W C++ dostępne są alternatywy dla macierzy C, takich jak std::vector i std::array. Ale nawet gdy masz (legacy) C tablicę masz 2 sytuacje:

  • jeśli przekazać go do funkcji C nie mają możliwość odniesienia, tak utkniesz do + wskaźnik wielkości
  • kiedy chcesz przekazać go do funkcji C++, idiomatyczny sposób C++ ma przekazywać wskaźniki początku i końca.

Przede wszystkim iteratory begin + end są ogólne, akceptuje wszelkiego rodzaju kontenery. Ale nie jest rzadkością odniesienie do std::vector, gdy chcesz uniknąć szablonów, więc dlaczego nie odwołać się do tablicy C, jeśli masz? Z powodu dużej wady: musisz znać rozmiar tablicy:

void foo(int (&arr)[5]) 

który jest wyjątkowo ograniczający.

Aby obejść ten problem trzeba zrobić to szablon:

template <std::size N> 
void foo(int (&arr)[N]) 

który bije w celu uniknięcia szablonów, więc lepiej iść z rozpoczęciem + iteratory szablonów koniec zamiast.


W niektórych przypadkach (np obliczeń matematycznych na zaledwie 2 lub 3 wartości, które mają te same semantykę, więc nie powinny być oddzielne parametry) A specyficzny rozmiar tablicy jest wymagana, a czyniąc funkcja generic nie miałaby sensu. W takich przypadkach określenie rozmiaru tablicy gwarantuje bezpieczeństwo, ponieważ pozwala tylko przekazać tablicę o poprawnym rozmiarze podczas kompilacji; Dlatego jest to korzystne i nie jest „wielka wada”

Jednym z uroków (C i C++) jest ogromny zakres stosowalności. Więc tak, zawsze znajdziesz pola, które używają lub potrzebują unikalnej funkcji w wyjątkowy sposób. Biorąc to pod uwagę, nawet w twoim przykładzie nadal unikałbym tablic. Kiedy masz ustaloną liczbę wartości, które nie powinny być oddzielone semantycznie, myślę, że struktura byłaby właściwym wyborem w stosunku do tablic przez większość czasu (np. glm::mat4 zamiast float[4]).

Ale nie zapominajmy, co to jest std::array: nowoczesny zamiennik macierzy C. Jedną z rzeczy, których nauczyłem się podczas analizowania opcji, jest to, że nie ma absolutnego "lepszego niż". Zawsze jest "zależy". Ale nie w tym przypadku: std::array powinien niewątpliwie zastąpić tablice C w interfejsach. Tak więc w rzadkim przypadku, gdy jako parametr referencyjny potrzebny jest kontener o ustalonym rozmiarze, nie ma sensu, aby umożliwić zachęcanie do korzystania z macierzy C, gdy już masz std::array. Tak więc jedynym ważnym przypadkiem, w którym wystawienie podstawowej tablicy C z std::array jest potrzeba, jest dla niektórych starych bibliotek, które mają parametry odniesienia C tablicy. Myślę jednak, że w szerszym kontekście dodanie tego do interfejsu nie jest uzasadnione. Nowy kod powinien używać struct (btw std::tuple jest coraz łatwiejszy w użyciu dla każdego standardu) lub std::array.

+2

W niektórych przypadkach (np. Obliczenia matematyczne na 2 lub 3 wartościach, które mają tę samą semantykę, więc nie powinny być oddzielnymi parametrami) wymagany jest określony rozmiar tablicy, a funkcja jest generyczna To ma sens. W takich przypadkach określenie rozmiaru tablicy gwarantuje bezpieczeństwo, ponieważ pozwala ona tylko na przekazanie tablicy o poprawnym rozmiarze podczas kompilacji; dlatego jest korzystny i nie jest "wielką wadą". – Danra

+0

@Danra dobry punkt. Zintegrował swój komentarz w odpowiedzi. – bolov

+2

Chciałbym tylko zwrócić uwagę, że nawet w obszarze C [można wziąć _pointer_ do tablicy o określonym rozmiarze, używając niemal identycznej składni do odwołania się do tablicy o określonym rozmiarze w C++] (http://rextester.com/MHUBK79249); niestety przekazanie wskaźnika do tablicy o innym rozmiarze jest traktowane jako ostrzeżenie zamiast błędu w każdym znanym kompilatorze. –

3

Nie ma ani jednego.

Rozumiem, dlaczego byłaby przydatna, szczególnie podczas pracy ze starszym kodem, ale od kilkudziesięciu lat powinniśmy odchodzić od takiego kodu iw kierunku algorytmów świadomych iteratora. A podczas pracy z kodem C i tak musiałbyś użyć wskaźnika. Zakładam, że są to czynniki decydujące o rezygnacji z tej funkcji.

Przepisz swój kod, aby zaakceptować std::array<T, N>& zamiast tego, jeśli to możliwe.

Powiązane problemy