2017-02-22 78 views
7

Załóżmy, że mam funkcję API biblioteki C, która przyjmuje wskaźnik wskaźników jako parametr. Ponieważ jednak programuję w C++, chciałbym skorzystać z wektora std, aby poradzić sobie z pamięcią dynamiczną. Jak mogę skutecznie przekonwertować wektor wektora na wskaźnik wskaźnika? Teraz używam tego.Konwertuj wektor wektora na wskaźnik wskaźnika

#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; 
} 

Czy to najlepszy sposób na osiągnięcie celu? Czy mogę pozbyć się "nowego usunięcia", używając w tym przypadku iteratora lub jakiejś metody std? Z góry dziękuję.

Edytuj: Zgodnie z odpowiedziami używam teraz tej wersji do interfejsu z kodem C. Zamieszczam to tutaj.

#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; 
} 

Wygląda bardziej na C++ jak dla mnie. Dzięki za wszystko!

+3

upuść jeden poziom wektora i wziąć adres wskaźnik do pierwszego elementu tej płaskiej wektorze. – rubenvb

+0

Tylko dzięki temu, że wygląda ładniej, możesz zastąpić psPtr wektorem i ustawić go przy pomocy pewnej funkcji w algorytmie. – BlueWanderer

+0

Funkcja API albo potrzebuje parametru o rozmiarze, albo ma konwencję, że zerowy wskaźnik oznacza ostatni element, w którym to przypadku musisz dodać 'nullptr' na końcu. –

Odpowiedz

4

Czy to najlepszy sposób na osiągnięcie celu?

Jeśli jesteś pewien, że wektor wektorów przeżyje psPtr, to tak. W przeciwnym razie istnieje ryzyko, że psPtr będzie zawierać nieprawidłowe wskaźniki.

Czy mogę pozbyć się "nowego usunięcia", używając w tym przypadku iteratora lub jakiejś metody standardowej?

Tak. Proponuję przy użyciu:

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

a następnie użyć &psPtr[0] w wywołaniu funkcji C API. To usuwa obciążenie zarządzania pamięcią ze swojego kodu.

foo(&psPtr[0]);   
+0

To wygląda całkiem schludnie. Nigdy nie myślałem o wektorze wskaźnika wcześniej. Dzięki! – yc2986

+0

@ yc2986, nie ma za co. –

+0

@ yc2986: Wektor wskaźników jest zwykle anty-wzorem. Jeśli nigdy nie myślałeś o zrobieniu tego, jest to naprawdę dobra rzecz. – IInspectable

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

foo(&vecOfPtrs[0]); 
+0

Ponieważ znasz rozmiar kontenera 'vecOfPtrs' przed czasem, powinieneś zainicjować go do tego rozmiaru. Zapobiega to potencjalnym przemieszczeniom pamięci i potencjalnym wyjątkom z powodu zmiany rozmiaru. – IInspectable

+0

Dlaczego 'i vec [0]' a nie 'vec.data()'? Mogę wymyślić co najmniej 3 powody używania 'vec.data() 'over' i vec [0] ', i zero, aby użyć' i vec [0] 'przez' vec.data() '. (puste wektory, 'vector ', 'std :: addressof', w malejącym znaczeniu) – Yakk

+0

@Yakk Przypuszczam, że stare nawyki umierają ciężko z C++ 03. 'vec.data()' jest lepszy. Jednak twój pierwszy powód nie jest wcale dobry, ponieważ 'vec.data()' powinno zwracać '& vec [0]', nawet dla pustego wektora, a standard C++ pozwala na przyjęcie adresu jednej-przeszłości-końca tablicy. – rlbond