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?
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?
Odpowiedzi:
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.”.
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, że c_arr
kopiowanie nie jest drogie. Jednak cpp_arr[i]
kopiowanie będzie bardzo kosztowne.
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ć go std::array
do przekazania referencji, jeśli tego chcesz.
std::size_t
zamiast tego int
? 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()
a size()
wszystkie wartości bezsensowne powrotne gdy gniazdo std::array
.
Z tych powodów utworzyłem własne wielowymiarowe kontenery tablic o stałym rozmiarze array_2d
i array_3d
. Są analogiczne do std::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:
arr[x][y]
, nie możesz stwierdzić, czy arr
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 z std::vector<>
.
Podczas gdy pierwszy przykład można stosunkowo łatwo wyrazić w C ++ (aczkolwiek wymaga new[]
i delete[]
), 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.
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
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
std::array
będzie mniej wydajna niż tablica C.
at()
, nie ma go operator[]
, tak jak std::vector
. Nie ma spadku wydajności ani nadmiaru kodu std::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.