Доступ к вектору & lt; vector & lt; int & gt; & gt; как плоский массив

Для этого массива:

vector<vector<int> > v;

v.push_back(vector<int>(0));
v.back().push_back(1);
v.back().push_back(2);
v.back().push_back(3);
v.back().push_back(4);

Я могу вывести {1, 2, 3, 4} достаточно легко:

cout << v[0][0] << endl;
cout << v[0][1] << endl;
cout << v[0][2] << endl;
cout << v[0][3] << endl;

Чтобы получить доступ к нему как к плоскому массиву, я могу сделать это:

int* z = (int*)&v[0].front();

cout << z[0] << endl;
cout << z[1] << endl;
cout << z[2] << endl;
cout << z[3] << endl;

Теперь, как я могу получить доступ к многомерному вектору в виде плоского многомерного массива? Я не могу использовать тот же формат, что и для доступа к одномерному вектору:

// This does not work (outputs garbage)
int** n = (int**)&v.front();

cout << n[0][0] << endl;
cout << n[0][1] << endl;
cout << n[0][2] << endl;
cout << n[0][3] << endl;

Обходной путь, который я нашел, должен сделать это:

int** n = new int* [v.size()];

for (size_t i = 0; i < v.size(); i++) {
n[i] = &v.at(i).front();
}

cout << n[0][0] << endl;
cout << n[0][1] << endl;
cout << n[0][2] << endl;
cout << n[0][3] << endl;

Есть ли способ получить доступ ко всему многомерному вектору, например, к плоскому массиву в стиле c, без необходимости динамически размещать каждое измерение над данными, прежде чем получить к нему доступ?

Скорость не имеет решающего значения при реализации, и ясность для обслуживания имеет первостепенное значение. Многомерный вектор прекрасно подходит для хранения данных. Однако я хочу также представить данные в виде плоского массива в стиле c в SDK, чтобы они были легко доступны для других языков. Это означает, что показывать векторы как объект STL не стоит.

Решение, которое я придумала, отлично подходит для моих нужд, так как я вычисляю массив только один раз в самом конце обработки, чтобы «сгладить» его. Тем не менее, есть ли лучший способ пойти по этому поводу? Или я уже делаю это наилучшим образом, чем могу, без повторной реализации моей собственной структуры данных (излишнее, поскольку мой плоский код состоит всего из нескольких строк).

Спасибо за ваш совет, друзья!

1

Решение

vectorВ общем случае буфер распределяется динамически.

Это означает, что когда у вас есть vector из vectors, то в отношении внутренних буферов у вас есть что-то похожее на массив указателей, каждый указатель указывает на массив.

Если вам необходимо переключаться между одномерным и двухмерным видами одних и тех же данных, возможно, проще всего просто определить класс двумерного массива, например так (без манжеты):

typedef ptrdiff_t Size;
typedef Size Index;

template< class Item >
class Array2D
{
private:
std::vector< Item > items_;
Size                width_;
Size                height_;

Index indexFor( Index const x, Index const y )
{ return y*width_ + x; }

public:
Size width() const { return width_; }
Size height() const { return height_; }

Item& operator()( Index const x, Index const y )
{ return items_[indexFor( x, y )]; }

Item const& operator()( Index const x, Index const y ) const
{ return items_[indexFor( x, y )]M; }

Size bufferSize() const { return width_*height_; }
Item* buffer() { return &items_[0]; }
Item const* buffer() const { return &items_[0]; }

Array2D( Size const w, Size const h )
: items_( w*h )
, width_( w )
, height_( h )
{}
};

Тогда вы можете делать такие вещи, как

Array2D< int >  a( 4, 3 );

for( Index y = 0;  y < a.height();  ++y )
{
for( Index x = 0;  x < a.width();  ++x )
{
foo( a( x, y ) );
}
}

а также

Array2D< int >  a( 4, 3 );

int* const pb = a.buffer();
for( Index i = 0;  i < a.bufferSize();  ++i )
{
foo( pb[i];
}
3

Другие решения

Ну, вы не можете, потому что, хотя векторы гарантированно хранят свои элементы в непрерывной памяти, вектор векторов не гарантирует тот же макет хранения, что и у двумерного массива в стиле C.

Так что нет, это невозможно, и я бы пошел еще дальше и сказал, что int* z = (int*)&v[0].front(); просто безобразно

0

Если ваши 1d векторы (std::vector<int>) имеют одинаковый размер — тогда сохраните в массивах vector raw:

typedef int ARRAY[6];
std::vector<ARRAY> yourVector;

Если их размеры не идентичны — тогда у вас есть реальная проблема, так как каждый std::vector<int> занимают смежные области памяти, но эти зоны не являются смежными. Точно так же, как в этих сырых массивах C:

int** a = new int*[3];
a[0] = new int[4];
a[1] = new int[5];

a не указывает на непрерывную память размера (4+5)*sizeof(int)

0

Теперь, как я могу получить доступ к многомерному вектору в виде плоского многомерного массива?

Ты не можешь

Причина, по которой вы можете получить доступ vector<int> как int[] потому что макет такой же. Макет памяти vector<vector<int>> отличается от макета int*[]Это означает, что вы не можете получить к нему доступ, как если бы он был int*[],

Если вы не можете избежать доступа к данным через int*[] то, что вы делаете, выделяя массив int* и заполнение его указателями на векторы — лучшее, что вы можете сделать. Было бы лучше, если бы вы могли избежать необходимости делать это в первую очередь.

Вы можете использовать безопасный держатель исключений для int*[], Вам также, вероятно, не нужно использовать vector::at() и вы можете подумать, нужно ли вам обрабатывать случай, когда один из векторов пуст. Здесь я решаю эти проблемы, используя возможности C ++ 11.

std::unique_ptr<int*[]> n(new int* [v.size()]);
transform(begin(v), end(v), n.get(), [](std::vector<int> &i) { return i.data(); });
0
По вопросам рекламы [email protected]