std::array
значительно превосходит массивы C. И даже если я хочу взаимодействовать с устаревшим кодом, я могу просто использовать std::array::data()
. Есть ли причина, по которой мне когда-либо понадобится массив старой школы?
std::array
значительно превосходит массивы C. И даже если я хочу взаимодействовать с устаревшим кодом, я могу просто использовать std::array::data()
. Есть ли причина, по которой мне когда-либо понадобится массив старой школы?
Ответы:
Если я что-то не пропустил (я не слишком внимательно следил за самыми последними изменениями в стандарте), большинство применений массивов стиля C все еще остаются. std::array
допускает статическую инициализацию, но по-прежнему не учитывает инициализаторы. И поскольку раньше массивы в стиле C реально использовались только std::array
для статически инициализированных таблиц в следующих строках:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
используя обычные begin
и end
шаблонные функции (принятые в C ++ 11) для их перебора. Не говоря уже о размере, который компилятор определяет по количеству инициализаторов.
EDIT: еще одна вещь, которую я забыл: строковые литералы по-прежнему являются массивами в стиле C; т.е. с типом char[]
. Я не думаю, что кто-то исключил бы использование строковых литералов только потому, что у нас это есть std::array
.
const char[]
Нет. Говоря прямо. И в 30 символах.
Конечно, вам нужны массивы C для реализации std::array
, но на самом деле это не причина, по которой пользователю когда-либо понадобятся массивы C. Кроме того, нет, std::array
он не менее производительный, чем массив C, и имеет возможность доступа с проверкой границ. И, наконец, для любой программы на C ++ вполне разумно зависеть от стандартной библиотеки - в этом смысле она является стандартной - и если у вас нет доступа к стандартной библиотеке, то ваш компилятор не соответствует требованиям и вопрос помечен как «C ++», а не «C ++ и те вещи, которые не относятся к C ++, которые пропускают половину спецификации, потому что считают это неуместным».
std::array
в автономной реализации C ++ 11.
Похоже, что с массивами C использовать многомерные массивы проще, чем с std::array
. Например,
char c_arr[5][6][7];
в отличие от
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
Также из-за свойства автоматического распада массивов C c_arr[i]
в приведенном выше примере будет распадаться на указатель, и вам просто нужно передать оставшиеся измерения как еще два параметра. Я хочу сказать c_arr
, что копирование обходится недорого. Однако cpp_arr[i]
копирование будет очень затратным.
array
функции без потери размеров. И если вы передадите его в шаблон функции, то эта функция сможет вывести как размер, так и размер каждого измерения или только одно из них. Это может быть интересно для научных библиотек шаблонов, которые в основном работают с произвольными измерениями.
template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
должен решить любую из этих проблем.
c_arr
является очень дорогим для копирования! Для этого вы должны предоставить код самостоятельно. Указатель, на который он будет распадаться, является более близким эквивалентом ссылки, чем копия, и вы можете использовать его std::array
для передачи ссылки, если это то, что вы хотите.
std::size_t
вместо этого int
? извините за придирки, но это сделало бы его универсальным.
size_t
если хотите, хотя я не могу представить, что существует множество сценариев, в которых необходимы массивы с более чем 4 миллиардами строк или столбцов.
Как сказал Сумант, многомерные массивы намного проще использовать со встроенными C-массивами, чем с std::array
.
При вложении std::array
может стать очень трудным для чтения и излишне многословным.
Например:
std::array<std::array<int, 3>, 3> arr1;
по сравнению с
char c_arr[3][3];
Также обратите внимание на это begin()
, end()
и size()
все они возвращают бессмысленные значения при вложении std::array
.
По этим причинам я создал свои собственные контейнеры многомерных массивов фиксированного размера array_2d
и array_3d
. Они аналогичны, std::array
но для многомерных массивов из 2 и 3 измерений. Они более безопасны и имеют не худшую производительность, чем встроенные многомерные массивы. Я не включил контейнер для многомерных массивов с размерами больше 3, поскольку они необычны. В C ++ 0x можно создать вариативную версию шаблона, которая поддерживает произвольное количество измерений.
Пример двухмерного варианта:
//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 }
}};
Полная документация доступна здесь:
http://fsma.googlecode.com/files/fsma.html
Вы можете скачать библиотеку здесь:
arr[x][y]
вы не можете сказать, arr
является ли это массивом массивов, массивом указателей, указателем на массив или указателем на указатель; все для реализации законны, в зависимости от ваших потребностей. И, вероятно, в большинстве реальных случаев использования многомерных массивов размер необходимо определять во время выполнения.
Массивы в стиле C, доступные в C ++, на самом деле гораздо менее универсальны, чем настоящие массивы C. Разница в том, что в C типы массивов могут иметь размеры во время выполнения . Ниже приведен допустимый код C, но он не может быть выражен ни с помощью массивов C-стиля C ++, ни с помощью array<>
типов C ++ :
void foo(int bar) {
double tempArray[bar];
//Do something with the bar elements in tempArray.
}
В C ++ вам нужно будет разместить временный массив в куче:
void foo(int bar) {
double* tempArray = new double[bar];
//Do something with the bar elements behind tempArray.
delete[] tempArray;
}
Этого нельзя достичь с помощью std::array<>
, потому что bar
это неизвестно во время компиляции, для этого требуется использование массивов в стиле C в C ++ или std::vector<>
.
В то время как первый пример относительно легко может быть выражен на C ++ (хотя и требует new[]
и delete[]
), следующее не может быть достигнуто на C ++ без std::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);
}
Дело в том, что указатели на линейные массивы int (*)[width]
не могут использовать ширину времени выполнения в C ++, что делает любой код манипулирования изображениями намного более сложным в C ++, чем в C. Типичная реализация примера манипулирования изображениями C ++ будет выглядеть следующим образом:
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;
}
Этот код выполняет в точности те же вычисления, что и приведенный выше код на C, но он должен выполнять вычисление индекса вручную, где бы они ни использовались . В случае 2D это все еще возможно (хотя и дает много возможностей ошибиться при вычислении индекса). Однако в случае с 3D это становится действительно неприятно.
Мне нравится писать код на C ++. Но всякий раз, когда мне нужно манипулировать многомерными данными, я действительно спрашиваю себя, следует ли мне перенести эту часть кода на C.
gcc
например). C11 сделал довольно много интересных вещей необязательными, и я не думаю, что это потому, что они хотят объявить эту функцию вне закона. Я склонен рассматривать это как знак того, что они хотели снизить уровень написания полностью совместимого со стандартами компилятора: VLA довольно сложно реализовать, и большая часть кода может обойтись без него, поэтому имеет смысл для нового компилятора на некоторых новых платформу, чтобы не нужно было сразу внедрять VLA.
Может быть, std::array
не медленный. Но я провел несколько тестов, используя простое сохранение и чтение из массива std :: array; См. Результаты теста ниже (на W8.1, обновление 4 VS2013):
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
Судя по отрицательным отметкам, код, который я использовал, находится в pastebin ( ссылка )
Код тестового класса здесь ;
Я не очень разбираюсь в тестах ... Мой код может быть некорректным
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
настоящее. Вам действительно нужно перепрыгнуть через обручи, чтобы убедиться, что код, который вы измеряете, является кодом, который вы хотите измерить.
std::array
std::array
будет менее производительно, чем массив C.
at()
, это не так operator[]
, просто как std::vector
. Нет никакого снижения производительности или раздувания кода std::array
, компилятор предназначен для оптимизации такого рода вещей. И, конечно же, добавление проверенной функции - отличный инструмент для отладки и большое преимущество. @Lou Franco: Весь код C ++ может зависеть от стандартной библиотеки - вот для чего она нужна. @Earlz: Если у вас нет STL, значит, это не C ++, и на этом все.
std::array
его больше, чем эквивалентное использование массива C.