Когда производительность важна для приложения, следует ли учитывать, следует ли объявлять массив в стеке против кучи? Позвольте мне изложить, почему этот вопрос пришел на ум.
Поскольку массивы в C/С++ не являются объектами и распадаются на указатели, компилятор использует предоставленный индекс для выполнения арифметики указателя для доступа к элементам. Я понимаю, что эта процедура отличается от от статически объявленного массива до динамически объявленного массива при прохождении первого измерения.
Если я должен был объявить массив в стеке следующим образом:
int array[2][3] = { 0, 1, 2, 3, 4, 5 }
//In memory { row1 } { row2 }
Этот массив будет храниться в формате Row Major в памяти, поскольку он хранится в непрерывном блоке памяти. Это означает, что когда я пытаюсь получить доступ к элементу в массиве, компилятор должен выполнить некоторое сложение и умножение, чтобы определить правильное местоположение.
Итак, если бы я сделал следующее
int x = array[1][2]; // x = 5
Затем компилятор будет использовать эту формулу где:
i = индекс строки j = индекс столбца n = размер одной строки (здесь n = 2)
array = указатель на первый элемент
*(array + (i*n) + j)
*(array + (1*2) + 2)
Это означает, что если я должен был перебрать этот массив для доступа к каждому из его элементов, для каждого доступа по индексу выполняется дополнительный шаг умножения.
Теперь, в массиве, объявленном в куче, парадигма отличается и требует многоступенчатого решения. Примечание. Я мог бы также использовать новый оператор С++ здесь, но я считаю, что нет никакой разницы в том, как представлены данные.
int ** array;
int rowSize = 2;
// Create a 2 by 3 2d array on the heap
array = malloc(2 * sizeof(int*));
for (int i = 0; i < 2; i++) {
array[i] = malloc(3 * sizeof(int));
}
// Populating the array
int number = 0;
for (int i = 0; i < 2; i++) {
for (int j = 0l j < 3; j++) {
array[i][j] = number++;
}
}
Поскольку массив теперь динамический, его представление представляет собой одномерный массив одномерных массивов. Я попытаюсь нарисовать изображение ascii...
int * int int int
int ** array-> [0] 0 1 2
[1] 3 4 5
Это означает, что умножение больше не задействовано? Если бы я сделал следующее
int x = array[1][1];
Затем будет выполняться арифметика косвенности/указателя на массиве [1], чтобы получить доступ к указателю на вторую строку, а затем выполнить это еще раз, чтобы получить доступ ко второму элементу. Правильно ли я это говорю?
Теперь, когда есть какой-то контекст, вернемся к вопросу. Если я пишу код для приложения, для которого требуется четкая производительность, например игра, которая имеет около 0,016 секунды для рендеринга фрейма, я должен дважды подумать об использовании массива в стеке против кучи? Теперь я понимаю, что для использования malloc или нового оператора существует однократная стоимость, но в определенный момент (как и анализ Big O), когда набор данных становится большим, лучше ли было бы переходить через динамический массив, чтобы избежать значительного числа строк индексация?