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 ++, які пропускають половину специфікації, оскільки вважали це недоречним."
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 типи масивів можуть мати розміри середовища виконання . Нижче наведено дійсний код С, але він не може бути виражений ні масивами в стилі С ++ С, ні array<>
типами С ++ :
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, VS2013, оновлення 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
Відповідно до негативних оцінок, код, який я використовував, знаходиться в пастебіні ( посилання )
Код базового класу знаходиться тут ;
Я не дуже багато знаю про бенчмаркінги ... Мій код може бути хибним
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.