В то время как многомерный массив представляет собой иерархию контейнеров элементов, в какой-то момент элементы должны быть выложены в память. В результате один многомерный массив может быть представлен в памяти более чем одним способом.
Например, рассмотрим двухмерный массив, показанный ниже в матричных обозначениях:
Вот как вышеупомянутый массив выражается в C++:
int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
Это пример хранения строк, где элементы каждой строки хранятся сопряжённо. В то время как C++ прозрачно обрабатывает доступ к элементам массива, вы также можете управлять массивом и его индексацией вручную. Один из способов выразить это в памяти заключается в следующем:
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
int s[] = { 4, 1 };
С последней декларацией a
и шагами s
можно получить доступ к элементу a(i,j)
массива с помощью выражения
*a+i*s[0]+j*s[1]
.
Один и тот же двухмерный массив может быть выложен колонкой следующим образом:
int a[] = { 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11 };
int s[] = { 3, 1 };
Обратите внимание, что здесь шаги разные. В результате выражение, приведенное выше для значений доступа, будет работать с этой парой данных.
В дополнение к порядку размерности также можно хранить любое измерение в порядке убывания. Например, возвращаясь к первому примеру, первое измерение примерного массива, строки, могут быть сохранены в обратном порядке, в результате чего:
int data[] = { 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 };
int *a = data + 8;
int s[] = { -4, 1 };
Обратите внимание, что в этом примере a
должно быть явно установлено происхождение. В предыдущих примерах первым элементом, хранящимся в памяти, было происхождение; здесь это уже не так.
В качестве альтернативы, второе измерение или столбцы могут быть обращены вспять, и строки хранятся в порядке возрастания:
int data[] = { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8 };
int *a = data + 3;
int s[] = { 4, -1 };
Наконец, оба измерения могут храниться в порядке убывания:
int data[] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
int *a = data + 11;
int s[] = { -4, -1 };
Все вышеперечисленные значения эквивалентны. Выражение, приведенное выше для a(i,j)
, дает одинаковое значение независимо от компоновки памяти. Повышаю. Массивы MultiArray могут быть созданы с настраиваемыми параметрами хранения, как описано выше. Таким образом, существующие данные могут быть адаптированы (с multi_array_ref
или const_multi_array_ref
) в соответствии с абстракцией массива. Распространенным использованием этой функции будет обертывание массивов, которые должны взаимодействовать с рутинами Fortran, чтобы ими можно было естественно манипулировать как на уровне C++, так и на уровне Fortran. Следующие разделы описывают рост. Компоненты MultiArray используются для определения макета памяти.
class c_storage_order {
c_storage_order();
};
c_storage_order
используется для указания того, что массив должен хранить свои элементы, используя ту же компоновку, что и используемые примитивными многомерными массивами C++, то есть от последнего измерения до первого. Это порядок хранения по умолчанию для массивов, предоставляемых этой библиотекой.
class fortran_storage_order {
fortran_storage_order();
};
fortran_storage_order
используется для указания того, что массив должен хранить свои элементы с использованием той же компоновки памяти, что и многомерный массив Fortran, то есть от первого измерения до последнего.
template <std::size_t NumDims>
class general_storage_order {
template <typename OrderingIter, typename AscendingIter>
general_storage_order(OrderingIter ordering, AscendingIter ascending);
};
general_storage_order
позволяет пользователю задать произвольный макет памяти для содержимого массива. Построенный объект передается конструктору массива для того, чтобы указать порядок хранения.
OrderingIter
и AscendingIter
должны смоделировать концепцию InputIterator
. Оба итератора должны относиться к диапазону элементов NumDims
. AscendingIter
указывает на объекты, конвертируемые в bool
. Значение true
означает, что измерение хранится в порядке возрастания, а false
означает, что измерение хранится в порядке убывания. OrderingIter
определяет порядок, в котором хранятся размеры.