Передать вложенный вектор C ++ как многомерный массив встроенного стиля - PullRequest
2 голосов
/ 25 апреля 2011

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

void some_function(size_t size, int array[])
{
    // impl here...
}

// ...
std::vector<int> test;
some_function(test.size(), &test[0]);

Безопасно ли делать это с вложенным вектором?

void some_function(size_t x, size_t y, size_t z, int* multi_dimensional_array)
{
    // impl here...
}

// ...

std::vector<std::vector<std::vector<int> > > test;
// initialize with non-jagged dimensions, ensure they're not empty, then...
some_function(test.size(), test[0].size(), test[0][0].size(), &test[0][0][0]);

Редактировать:

Если это небезопасно, каковы некоторые альтернативы, как если я могу изменить подпись some_function, и если я не могу?

Ответы [ 8 ]

1 голос
/ 25 апреля 2011

Ошибочно брать адрес любого местоположения в векторе и передавать его. Может показаться, что это работает, но не рассчитывайте на это.

Причина, по которой тесно связана с тем, почему вектор является вектором, а не массивом. Мы хотим, чтобы вектор рос динамически, в отличие от массива. Мы хотим, чтобы вставки в вектор имели постоянную стоимость и не зависели от размера вектора, например, массива, пока вы не достигнете выделенного размера массива.

Так как же работает магия? Когда больше нет внутреннего пространства для добавления следующего элемента в вектор, новое пространство выделяется в два раза больше старого. Старое пространство копируется в новое, а старое пространство больше не требуется и не действует, что делает висящий любой указатель на старое пространство. Дважды выделяется пространство, поэтому средняя стоимость вставки в вектор, который является постоянной величиной.

1 голос
/ 25 апреля 2011

Очень простым решением было бы просто скопировать содержимое вложенного вектора в один вектор и передать его этой функции. Но это зависит от того, сколько накладных расходов вы готовы взять.

Это печально: вложенные векторы не являются хорошей практикой. Класс матрицы, хранящий все в смежной памяти и управляющий доступом, действительно более эффективен и менее уродлив и, возможно, допускает что-то вроде T* matrix::get_raw(), но упорядочение содержимого все равно будет деталью реализации.

1 голос
/ 25 апреля 2011

Можно ожидать, что multi_dimensional_array будет указывать только на непрерывный блок памяти размером test[0][0].size() * sizeof(int).Но это, вероятно, не то, что вы хотите.

1 голос
/ 25 апреля 2011

Краткий ответ «нет».

Элементы здесь std::vector<std::vector<std::vector<int> > > test; не заменяются в смежной области памяти.

1 голос
/ 25 апреля 2011

Безопасно ли делать это с вложенным вектором?

Да, если вы хотите получить доступ только к внутреннему вектору и до тех пор, пока вызнать количество элементов, которые он содержит, и вы не пытаетесь получить доступ больше, чем это.

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

Альтернативой является то, что вы можете вызывать функциюsome_function(size_t size, int array[]) для каждого самого внутреннего вектора (если это решает вашу проблему);и для этого вы можете сделать этот трюк (или что-то подобное):

void some_function(std::vector<int> & v1int)
{
    //the final call to some_function(size_t size, int array[]) 
    //which actually process the inner-most vectors
    some_function(v1int.size(), &v1int[0]);
}
void some_function(std::vector<std::vector<int> > & v2int)
{
    //call some_function(std::vector<int> & v1int) for each element!
    std::for_each(v2int.begin(), v2int.end(), some_function);
}

//call some_function(std::vector<std::vector<int> > & v2int) for each element!
std::for_each(test.begin(), test.end(), some_function);
0 голосов
/ 06 мая 2011

Попытка использовать &top_level_vector[0] и передать это функции в стиле C, которая ожидает, что int* небезопасно.

Чтобы обеспечить правильный доступ в C-стиле к многомерному массиву, все байты всей иерархии массивов должны быть смежными. В c ++ std::vector это верно для элементов , содержащихся в векторе, но не для самого вектора. Если вы попытаетесь взять адрес вектора верхнего уровня, ala &top_level_vector[0], вы получите массив векторов, а не массив int.

Векторная структура - это не просто массив содержимого типа. Он реализован в виде структуры, содержащей указатель, а также данные учета размеров и емкости. Поэтому вопрос std::vector<std::vector<std::vector<int> > > является более или менее иерархическим деревом структур, сшитых вместе с указателями. Только конечные конечные узлы в этом дереве являются блоками смежных значений int. И каждый из этих блоков памяти не обязательно является смежным с любым другим блоком.

Для взаимодействия с C вы можете передать только содержимое одного vector. Таким образом, вам придется создать один std::vector<int> размером x * y * z. Или вы можете реструктурировать свой код C для обработки одной одномерной полосы данных за раз. Тогда вы сможете сохранить иерархию и передать только содержимое листовых векторов.

0 голосов
/ 25 апреля 2011

Было бы намного безопаснее передать вектор или ссылку на него:

void some_function(std::vector<std::vector<std::vector<int>>> & vector);

Затем вы можете получить размер и элементы в функции, оставляя меньше риска для ошибок. Вы можете скопировать вектор или передать указатель / ссылку, в зависимости от ожидаемого размера и использования.

Если вам нужно пройти через модули, то это становится немного сложнее.

0 голосов
/ 25 апреля 2011

Простой ответ - нет, это не так. Вы пытались это скомпилировать? И почему бы просто не передать весь трехмерный вектор в качестве эталона? Если вы пытаетесь получить доступ к старому коду C таким способом, вы не можете.

...