std :: вектор и непрерывная память многомерных массивов

Я знаю, что стандарт не заставляет std::vector выделять смежные блоки памяти, но все реализации все равно подчиняются этому.

Предположим, что я хочу создать вектор многомерного статического массива. Рассмотрим 2 измерения для простоты и вектор длины N. Это я хочу создать вектор с N элементами, например, int[5] .

Могу ли я быть уверенным, что все N * 5 целые числа теперь смежны в памяти? Чтобы я в принципе мог получить доступ ко всем целым, просто зная адрес первого элемента? Является ли эта реализация зависимой?

Для справки, как я в настоящее время создаю 2D-массив в смежном блоке памяти, сначала создаем (динамический) массив float * длины N, выделяя все N * 5 поплавков в одном массиве и затем копируя адрес каждого 5-го элемента в первый массив float* .

Для справки, как я в настоящее время создаю 2D-массив в смежном блоке памяти, сначала создаем (динамический) массив float * длины N, выделяя все N * 5 поплавков в одном массиве и затем копируя адрес каждого 5-го элемента в первый массив float *.

Это не 2D-массив, это массив указателей. Если вам нужен настоящий 2D-массив, вот как это делается:

 float (*p)[5] = new float[N][5]; p [0] [0] = 42; // access first element p[N-1][4] = 42; // access last element delete[] p; 

Обратите внимание, что существует только одно выделение. Могу ли я предложить больше узнать об использовании массивов на C ++ ?

Стандарт требует, чтобы память std::vector была смежной. С другой стороны, если вы пишете что-то вроде:

 std::vector > v; 

глобальная память (все v[i][j] ) не будет смежной. Обычным способом создания 2D-массивов является использование одного

 std::vector v; 

и рассчитывать индексы, точно так же, как вы предлагаете делать с float . (Вы также можете создать второй std::vector с адресами, если хотите. Я всегда просто пересчитывал индексы.)

Элементы вектора гарантируют непрерывность в соответствии со стандартом C ++.
Котировки из стандарта заключаются в следующем:

Из n2798 (черновик C ++ 0x):

23.2.6 Вектор шаблона шаблона [вектор]

1 Вектор представляет собой контейнер последовательности, который поддерживает iteratorы с произвольным доступом. Кроме того, он поддерживает (амортизируется) постоянное время вставки и стирания операций в конце; вставлять и стирать в середине, принимать линейное время. Управление хранилищем обрабатывается автоматически, хотя можно дать подсказки для повышения эффективности. Элементы вектора сохраняются смежно, что означает, что если v – вектор, где T – некоторый тип, отличный от bool, то он подчиняется идентификатору & v [n] == & v [0] + n для всех 0 <= n

Стандарт C ++ 03 (23.2.4.1):

Элементы вектора сохраняются смежно, что означает, что если v – вектор, где T – некоторый тип, отличный от bool, то он подчиняется идентификатору & v [n] == & v [0] + n для всех 0 <= n

Кроме того, смотрите здесь то, что взгляды Херба Саттера на то же самое.

Как уже указывал @Als, да, std::vector (теперь) гарантирует непрерывное распределение. Однако я бы не смоделировал 2D-матрицу с массивом указателей. Вместо этого я бы рекомендовал один из двух подходов. Чем проще (безусловно) использовать operator() для подписи и делать умножение для преобразования двумерного ввода в линейный адрес в векторе:

 template  class matrix2D { std::vector data; int columns; public: T &operator()(int x, int y) { return data[y * columns + x]; } matrix2D(int x, int y) : data(x*y), columns(x) {} }; 

Если по какой-либо причине вы хотите использовать matrix[a][b] адресацию стиля, вы можете использовать прокси-class для обработки преобразования. Хотя это было для 3D-матрицы вместо 2D, я опубликовал демонстрацию этой техники в предыдущем ответе .

Под капотом вектор может выглядеть примерно как (p-код):

 class vector { T *data; size_t s; }; 

Теперь, если вы создадите vector > , будет такой макет, как этот

 vector> --> data { vector, vector, vector }; 

или в «вложенной» форме

 vector> --> data { {data0, s0}, {data1, s1}, {data2, s2} }; 

Да, вектор-вектор поэтому использует непрерывную память, но нет, не так, как вам бы хотелось. Скорее всего, он хранит массив указателей (и некоторых других переменных) во внешних местах.

Стандарт требует только того, чтобы данные вектора были смежными, но не вектором в целом.

Простой class для создания, как вы его называете, 2D-массива , будет выглядеть примерно так:

 template  2DArray { private: T *m_data; int m_stride; public: 2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {} ~2DArray() { delete[] m_data; } T* operator[](int row) { return m_data + m_stride * row; } } 

Это можно использовать так:

 2DArray myArray(30,20); for (int i = 0; i < 30; i++) for (int j = 0; j < 20; j++) myArray[i][j] = i + j; 

Или даже передать &myArray[0][0] качестве адреса для низкоуровневых функций, которые берут какие-то «плоские буферы».

Но, как вы видите, это myarray[y][x] наивным ожиданиям в том, что это myarray[y][x] .

В общем, если вы взаимодействуете с кодом, который требует своего рода classического плоского массива C-style, то почему бы просто не использовать его?

Изменить: Как сказано выше, все просто . Никакие ограничения не проверяют попытки вообще. Также как «массив».

  • Что же случилось с использованием GC.Collect ()?
  • Объясните эту реализацию malloc из книги K & R
  • Как получить доступную память C ++ / g ++?
  • Эффективные C ++ строки (интернирование, веревки, копирование на запись и т. Д.)
  • Где постоянные переменные хранятся в C?
  • Безопасно ли удалять указатель на пустоту?
  • Как я могу получить размер массива из указателя в C?
  • Динамический двумерный массив с указателем на указатель
  • Как работают realloc и memcpy?
  • C ++ Наведите несколько типов на вектор
  • Удаляет ли вызов деструктор?
  • Interesting Posts

    Почему десятичные числа не могут быть представлены точно в двоичном формате?

    Быстрый алгоритм прореживания

    Неожиданное свободное дисковое пространство уменьшается?

    Является ли это REST API действительно RPC? Рой Филдинг, кажется, так думает

    как отображать карту в android с маркером

    Ноутбук Windows 7 продолжает входить в спящий режим, даже несмотря на то, что настройки питания никогда не повторяются

    Подключение к компьютерам в другой сети маршрутизатора

    Есть ли преимущество использования Синхронизированного метода вместо Синхронизированного блока?

    Как я могу выполнить несколько одновременных эффектов jquery?

    Настройка пользовательского механизма поиска по умолчанию в Opera

    Как узнать, какое приложение Windows прослушивает конкретный порт TCP?

    Добавление параметров командной строки по умолчанию при открытии определенного типа файла

    ASP.NET перезапускается, когда папка создается, переименовывается или удаляется

    Почему Dropbox использует так много памяти в Linux?

    Будет ли этот автомобильный адаптер питания этого ноутбука?

    Давайте будем гением компьютера.