2017-02-22 57 views
7

Предположим, у меня есть функция API библиотеки C, которая принимает указатель указателей в качестве параметра. Однако, поскольку я программирую на C++, я бы хотел использовать std-вектор для работы с динамической памятью. Как я могу эффективно преобразовать вектор вектора в указатель указателя? Сейчас я использую это.Преобразование вектора вектора в указатель указателя

#include <vector> 

/* C like api */ 
void foo(short **psPtr, const int x, const int y);  

int main() 
{ 
    const int x = 2, y = 3; 
    std::vector<std::vector<short>> vvsVec(x, std::vector<short>(y, 0)); 
    short **psPtr = new short*[x]; 

    /* point psPtr to the vector */ 
    int c = 0; 
    for (auto &vsVec : vvsVec) 
     psPtr[c++] = &vsVec[0]; 

    /* api call */ 
    foo(psPtr, x, y);   

    delete[] psPtr; 
    return 0; 
} 

Это лучший способ для достижения цели? Могу ли я избавиться от вещи «нового удаления» с помощью итератора или какого-либо метода std в этом случае? Заранее спасибо.

Редактировать: Согласно ответам, я использую эту версию для взаимодействия с кодом C. Я размещаю его здесь.

#include <vector> 

/* C like api */ 
void foo(short **psPtr, const int x, const int y);  

int main() 
{ 
    const int x = 2, y = 3; 
    std::vector<std::vector<short>> vvsVec(x, std::vector<short>(y, 0)); 
    std::vector<short*> vpsPtr(x, nullptr); 

    /* point vpsPtr to the vector */ 
    int c = 0; 
    for (auto &vsVec : vvsVec) 
     vpsPtr[c++] = vsVec.data(); 

    /* api call */ 
    foo(vpsPtr.data(), x, y);   

    return 0; 
} 

Выглядит больше C++, как мне. Спасибо за все!

+3

Капля один уровень вектора и взять адрес указателя на первый элемент этого плоского вектора. – rubenvb

+0

Только сделать это лучше, вы можете заменить psPtr на вектор и настроить его с помощью некоторой функции в алгоритме. – BlueWanderer

+0

Функция API либо нуждается в параметре размера, либо имеет соглашение о том, что нулевой указатель обозначает последний элемент, и в этом случае вы должны добавить 'nullptr' в конце. –

ответ

4

Это лучший способ для достижения цели?

Если вы уверены, что вектор векторов перейдет в psPtr, тогда да. В противном случае вы рискуете, что psPtr будет содержать недопустимые указатели.

Могу ли я избавиться от вещи «нового удаления» с помощью итератора или какого-либо метода std в этом случае?

Да. Я предлагаю использовать:

std::vector<short*> psPtr(vvsVec.size()); 

, а затем использовать &psPtr[0] в вызове функции C API. Это устраняет нагрузку на управление памятью из вашего кода.

foo(&psPtr[0]);   
+0

Это выглядит довольно аккуратно. Никогда раньше не думал о векторе указателя. Благодаря! – yc2986

+0

@ yc2986, пожалуйста. –

+0

@ yc2986: Вектор указателей обычно является анти-шаблоном. Если вы никогда не думали об этом, это на самом деле хорошо. – IInspectable

3
std::vector<short*> vecOfPtrs; 
for (auto&& vec : vvsVec) 
    vecOfPtrs.push_back(&vec[0]); 

foo(&vecOfPtrs[0]); 
+0

Поскольку вы знаете размер контейнера 'vecOfPtrs' раньше времени, вы должны действительно инициализировать его до такого размера. Это предотвращает потенциальные перераспределения памяти и возможные исключения из-за изменения размера. – IInspectable

+0

Почему '& vec [0]', а не 'vec.data()'? Я могу придумать по крайней мере 3 причины использовать 'vec.data() 'over' & vec [0] 'и ноль для использования' & vec [0] 'over' vec.data() '. (пустые векторы, 'vector ', 'std :: addressof' проблемы, в уменьшающемся значении) – Yakk

+0

@Yakk Я думаю, что старые привычки сильно отличаются от C++ 03. 'vec.data()' превосходит. Однако ваша первая причина не очень хороша, так как 'vec.data()' должен возвращать '& vec [0]', даже для пустого вектора, а стандарт C++ позволяет принимать адрес одного-конца-конца массива. – rlbond