std::array
znacznie przewyższa tablice C. A nawet jeśli chcę współdziałać ze starszym kodem, mogę po prostu użyć std::array::data()
. Czy jest jakiś powód, dla którego chciałbym kiedykolwiek mieć tablicę ze starej szkoły?
źródło
std::array
znacznie przewyższa tablice C. A nawet jeśli chcę współdziałać ze starszym kodem, mogę po prostu użyć std::array::data()
. Czy jest jakiś powód, dla którego chciałbym kiedykolwiek mieć tablicę ze starej szkoły?
O ile czegoś nie przeoczyłem (nie śledziłem zbyt uważnie ostatnich zmian w standardzie), większość zastosowań tablic w stylu C nadal pozostaje. std::array
pozwala na statyczną inicjalizację, ale nadal nie będzie liczyć inicjatorów za Ciebie. A ponieważ jedyne rzeczywiste użycie tablic w stylu C wcześniej std::array
dotyczyło statycznie inicjowanych tabel w następujący sposób:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
używając funkcji zwykłych begin
i end
szablonów (przyjętych w C ++ 11) do iteracji po nich. Nie wspominając o rozmiarze, który kompilator określa na podstawie liczby inicjatorów.
EDYCJA: Kolejna rzecz, o której zapomniałem: literały łańcuchowe są nadal tablicami w stylu C; tj. z typem char[]
. Nie sądzę, aby ktokolwiek wykluczył używanie literałów ciągów tylko dlatego, że tak jest std::array
.
const char[]
Nie, żeby, uh, ująć to bez ogródek. I w 30 znakach.
Oczywiście do zaimplementowania potrzebne są tablice C
std::array
, ale nie jest to tak naprawdę powód, dla którego użytkownik kiedykolwiek chciałby mieć tablice C. Ponadto nie,std::array
nie jest mniej wydajna niż tablica C i ma opcję dostępu z kontrolą ograniczeń. I wreszcie, jest całkowicie uzasadnione, aby jakikolwiek program w C ++ zależał od biblioteki standardowej - w pewnym sensie chodzi o to, że jest to standardowa - i jeśli nie masz dostępu do biblioteki standardowej, to twój kompilator jest niezgodny i pytanie jest oznaczone jako „C ++”, a nie „C ++ i te rzeczy nie-C ++, które pomijają połowę specyfikacji, ponieważ uważają, że jest nieodpowiednie.”.źródło
std::array
w wolnostojącej implementacji C ++ 11.Wydaje się, że używanie tablic wielowymiarowych jest łatwiejsze w przypadku tablic w języku C niż
std::array
. Na przykład,char c_arr[5][6][7];
w przeciwieństwie do
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
Również ze względu na właściwość automatycznego rozpadu tablic C,
c_arr[i]
w powyższym przykładzie rozpadnie się do wskaźnika i wystarczy przekazać pozostałe wymiary jako dwa dodatkowe parametry. Chodzi mi o to, żec_arr
kopiowanie nie jest drogie. Jednakcpp_arr[i]
kopiowanie będzie bardzo kosztowne.źródło
array
bez utraty wymiarów. A jeśli przekażesz to do szablonu funkcji, funkcja ta może wydedukować zarówno wymiar, jak i rozmiar każdego wymiaru lub tylko jednego z nich dwóch. Może to być interesujące dla naukowych bibliotek szablonów, które pracują głównie na dowolnych wymiarach.template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
powinna rozwiązać każdy z tych problemów.c_arr
jest bardzo drogi do skopiowania! Aby to zrobić, musisz podać kod. Wskaźnik, na który się rozpadnie, jest bliższy referencji niż kopia i możesz użyć gostd::array
do przekazania referencji, jeśli tego chcesz.std::size_t
zamiast tegoint
? przepraszam za czepianie się, ale to uczyniłoby to uniwersalnym.size_t
jeśli chcesz, chociaż nie wyobrażam sobie, że istnieje wiele scenariuszy, w których potrzebne są tablice zawierające więcej niż 4 miliardy wierszy lub kolumn.Jak powiedział Sumant, wielowymiarowe tablice są o wiele łatwiejsze w użyciu z wbudowanymi tablicami C niż z
std::array
.Po zagnieżdżeniu
std::array
może stać się bardzo trudny do odczytania i niepotrzebnie rozwlekły.Na przykład:
std::array<std::array<int, 3>, 3> arr1;
w porównaniu do
char c_arr[3][3];
Należy również pamiętać, że
begin()
,end()
asize()
wszystkie wartości bezsensowne powrotne gdy gniazdostd::array
.Z tych powodów utworzyłem własne wielowymiarowe kontenery tablic o stałym rozmiarze
array_2d
iarray_3d
. Są analogiczne dostd::array
wielowymiarowych tablic 2 i 3 wymiarów, ale. Są bezpieczniejsze i nie mają gorszej wydajności niż wbudowane tablice wielowymiarowe. Nie załączyłem kontenera na wielowymiarowe tablice o wymiarach większych niż 3, ponieważ są one rzadkie. W C ++ 0x można by stworzyć wariadyczną wersję szablonu, która obsługuje dowolną liczbę wymiarów.Przykład wariantu dwuwymiarowego:
//Create an array 3 x 5 (Notice the extra pair of braces) fsma::array_2d <double, 3, 5> my2darr = {{ { 32.19, 47.29, 31.99, 19.11, 11.19}, { 11.29, 22.49, 33.47, 17.29, 5.01 }, { 41.97, 22.09, 9.76, 22.55, 6.22 } }};
Pełna dokumentacja jest dostępna tutaj:
http://fsma.googlecode.com/files/fsma.html
Możesz pobrać bibliotekę tutaj:
http://fsma.googlecode.com/files/fsma.zip
źródło
arr[x][y]
, nie możesz stwierdzić, czyarr
jest to tablica tablic, tablica wskaźników, wskaźnik do tablicy, czy wskaźnik do wskaźnika; wszystkie do realizacji są zgodne z prawem, w zależności od Twoich potrzeb. I prawdopodobnie większość rzeczywistych przypadków użycia tablic wielowymiarowych wymaga określenia rozmiaru w czasie wykonywania.Tablice w stylu C, które są dostępne w C ++, są w rzeczywistości znacznie mniej wszechstronne niż rzeczywiste tablice C. Różnica polega na tym, że w języku C typy tablic mogą mieć rozmiary w czasie wykonywania . Poniższy kod jest prawidłowym kodem w C, ale nie można go wyrazić za pomocą tablic w stylu C ++ C ani za pomocą
array<>
typów C ++ :void foo(int bar) { double tempArray[bar]; //Do something with the bar elements in tempArray. }
W C ++ musiałbyś alokować tymczasową tablicę na stercie:
void foo(int bar) { double* tempArray = new double[bar]; //Do something with the bar elements behind tempArray. delete[] tempArray; }
Nie można tego osiągnąć za pomocą
std::array<>
, ponieważbar
nie jest znana w czasie kompilacji, wymaga użycia tablic w stylu C w C ++ lub zstd::vector<>
.Podczas gdy pierwszy przykład można stosunkowo łatwo wyrazić w C ++ (aczkolwiek wymaga
new[]
idelete[]
), następujące nie mogą zostać osiągnięte w C ++ bezstd::vector<>
:void smoothImage(int width, int height, int (*pixels)[width]) { int (*copy)[width] = malloc(height*sizeof(*copy)); memcpy(copy, pixels, height*sizeof(*copy)); for(y = height; y--; ) { for(x = width; x--; ) { pixels[y][x] = //compute smoothed value based on data around copy[y][x] } } free(copy); }
Chodzi o to, że wskaźniki do tablic liniowych
int (*)[width]
nie mogą używać szerokości czasu wykonywania w C ++, co sprawia, że jakikolwiek kod do manipulacji obrazami jest znacznie bardziej skomplikowany w C ++ niż w C. Typowa implementacja C ++ przykładu manipulacji obrazem wyglądałaby tak:void smoothImage(int width, int height, int* pixels) { int* copy = new int[height*width]; memcpy(copy, pixels, height*width*sizeof(*copy)); for(y = height; y--; ) { for(x = width; x--; ) { pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x] } } delete[] copy; }
Ten kod wykonuje dokładnie te same obliczenia, co kod C powyżej, ale musi wykonać ręczne obliczenia indeksu gdziekolwiek indeksy są używane . W przypadku 2D jest to nadal wykonalne (mimo że wiąże się z wieloma możliwościami błędnego obliczenia wskaźnika). Jednak w przypadku 3D robi się naprawdę paskudnie.
Lubię pisać kod w C ++. Ale ilekroć muszę manipulować wielowymiarowymi danymi, naprawdę zadaję sobie pytanie, czy powinienem przenieść tę część kodu do C.
źródło
gcc
na przykład). C11 wprowadził całkiem sporo interesujących rzeczy opcjonalnych i nie sądzę, żeby to dlatego, że chcą zakazać tej funkcji. Zwykle postrzegam to jako znak, że chcieli obniżyć poziom pisania w pełni zgodnego ze standardami kompilatora: VLA to dość trudna bestia do zaimplementowania, a wiele kodu może się bez niego obejść, więc nowy kompilator ma sens na jakimś nowym platformy, aby nie musieć od razu wdrażać VLA.Może
std::array
to nie jest powolne. Ale wykonałem trochę testów porównawczych przy użyciu prostego magazynu i przeczytałem ze std :: array; Zobacz poniższe wyniki testów porównawczych (na W8.1, VS2013 Update 4):ARR_SIZE: 100 * 1000 Avrg = Tick / ARR_SIZE; test_arr_without_init ==>VMem: 5.15Mb ==>PMem: 8.94Mb ==>Tick: 3132 ==>Avrg: 0.03132 test_arr_with_init_array_at ==>VMem: 5.16Mb ==>PMem: 8.98Mb ==>Tick: 925 ==>Avrg: 0.00925 test_arr_with_array_at ==>VMem: 5.16Mb ==>PMem: 8.97Mb ==>Tick: 769 ==>Avrg: 0.00769 test_c_arr_without_init ==>VMem: 5.16Mb ==>PMem: 8.94Mb ==>Tick: 358 ==>Avrg: 0.00358 test_c_arr_with_init ==>VMem: 5.16Mb ==>PMem: 8.94Mb ==>Tick: 305 ==>Avrg: 0.00305
Zgodnie z negatywnymi znakami kod, którego użyłem, znajduje się w pastebinie ( link )
Kod klasy testu porównawczego jest tutaj ;
Nie wiem zbyt wiele o testach porównawczych ... Mój kod może być wadliwy
źródło
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
teraz. Naprawdę musisz przeskakiwać przez obręcze, aby upewnić się, że kod, który mierzysz, jest kodem, który chcesz zmierzyć.std::array
źródło
std::array
będzie mniej wydajna niż tablica C.at()
, nie ma gooperator[]
, tak jakstd::vector
. Nie ma spadku wydajności ani nadmiaru kodustd::array
, kompilator został zaprojektowany do optymalizacji tego rodzaju rzeczy. I oczywiście dodanie sprawdzonej funkcji jest doskonałym narzędziem do debugowania i dużą zaletą. @Lou Franco: Cały kod C ++ może zależeć od biblioteki Standard - do tego właśnie służy. @Earlz: Jeśli nie masz dostępnego STL, to nie jest to C ++ i na tym koniec.std::array
było większe niż równoważne użycie tablicy C.