2009-11-14 15 views
46

Chciałbym móc przekonwertować między std :: vector i jego tablicą C int * bez jawnego kopiowania danych.Konwersja między stacjami C++ std :: vector i C bez kopiowania

Czy std :: vector zapewnia dostęp do podstawowej tablicy C? Szukam coś takiego

vector<int> v (4,100) 
int* pv = v.c_array(); 

EDIT:

Ponadto, możliwe jest zrobić coś przeciwnego, to znaczy w jaki sposób mogę zainicjować std::vector z tablicy C bez kopiowania?

int pv[4] = { 4, 4, 4, 4}; 
vector<int> v (pv); 
+0

Występuje "problem" z tym związany: int pv [4] = {4, 4, 4, 4}; wektor v (pv); to faktycznie kopiuje zawartość pv na v ... po prostu musisz być tego świadomy – fho

Odpowiedz

77

można uzyskać wskaźnik do pierwszego elementu w następujący sposób:

int* pv = &v[0]; 

Ten wskaźnik jest ważny tylko tak długo, jak wektor nie jest przydzielona. Realokacja dzieje się automatycznie po włożeniu więcej elementów niż zmieści się w pozostałej pojemności nosiciela (czyli jeśli v.size() + NumberOfNewElements > v.capacity(). Można użyć v.reserve(NewCapacity) aby upewnić się, że wektor ma pojemność co najmniej NewCapacity.

Należy również pamiętać, że gdy wektor dostaje . zniszczone, podstawowa tablica zostanie usunięty także

+7

"dopóki nie dodasz dodatkowych elementów do wektora" - bez rezerwowania miejsca w pierwszej kolejności. Jeśli "reserve()", możesz dodać elementy do zarezerwowanej pojemności i zagwarantować, że referencje i iteratory będą nadal aktualne. –

+2

@Steve: Dobra uwaga. Tylko pamiętaj, aby zarezerwować() zanim otrzymasz wskaźnik! :) –

+0

@Steve: To prawda, choć myślę, że byłoby to trochę niepokojące, gdybym zobaczył kod wstawiający elementy do wektora _ i_ za pomocą wskaźników do elementów w wektorze, które zostały uzyskane przed wstawieniem. Mimo to zmodyfikowałem ten akapit, aby spróbować i wyraźniej określić, kiedy nastąpi realokacja. –

19
int* pv = &v[0] 

Należy pamiętać, że jest to tylko w przypadku std::vector<>, nie można zrobić to samo z innych pojemników standardowych.

Scott Meyers obszernie omawia ten temat w swoich książkach.

+2

Wierzę, że jest to gwarantowane działanie standardu. – Omnifarious

+0

"nie można zrobić tego samego z innymi standardowymi kontenerami" - IIRC będzie można zrobić to z ciągiem w C++ 0x, aw praktyce praktycznie każda implementacja faktycznie gwarantuje, że pamięć ciągów jest ciągła. –

+3

Możesz otrzymać tablicę tylko do odczytu zawierającą elementy 'std :: string' przy użyciu jej elementów' c_str() 'lub' data() '.Z tego powodu, chociaż standard nie wymaga ciągłego przechowywania ciągów w pamięci, byłoby to bardzo dziwne i nieskuteczne. –

14

Jeśli bardzo kontrolowane warunki, można po prostu zrobić:

std::vector<int> v(4,100); 
int* pv = &v[0]; 

być ostrzeżony, że to będzie działać tak długo, jak wektor nie musi wzrastać tylko, a wektor będzie nadal zarządzać żywotność z podstawowej tablicy (to znaczy, nie usuwaj pv). Nie jest to rzadkość podczas wywoływania podstawowych funkcji API C, ale zwykle odbywa się to przy użyciu nienazwanego tymczasowego, a nie poprzez utworzenie jawnej zmiennej int *.

0

Jednym ze sposobów zabezpieczania się przed zmianami wielkości jest zarezerwowanie maksymalnej przestrzeni (lub większe), które potrzebne będą:

std::vector<int> v(4,100); //Maybe need 
v.reserve(40);    //reallocate to block out space for 40 elements 

to zapewni, że push_backs wygrał powodują realokację o f istniejące dane.

15

W języku C++ 11 można użyć vector::data(), aby uzyskać wskaźnik tablicy C.

Powiązane problemy