Moje pytanie jest proste: czy elementy std :: vector są na pewno ciągłe? W słowie kolejności, czy mogę użyć wskaźnika do pierwszego elementu std :: vector jako tablicy C?
Jeśli moja pamięć dobrze mi służy, standard C ++ nie dawał takiej gwarancji. Jednak wymagania std :: vector były takie, że praktycznie niemożliwe było ich spełnienie, gdyby elementy nie były ciągłe.
Czy ktoś może to wyjaśnić?
Przykład:
std::vector<int> values;
// ... fill up values
if( !values.empty() )
{
int *array = &values[0];
for( int i = 0; i < values.size(); ++i )
{
int v = array[i];
// do something with 'v'
}
}
values
w tymif
bloku. Nie znam jednak odpowiedzi na twoje pytanie, więc zostawiam tylko komentarz. :)values
, a konkretnie zmieniają jego rozmiar (np.push_back()
), Mogą skłonić do ponownej alokacji wektora bazowego, który unieważnia wskaźnik skopiowany doarray
. Ta sama zasada obowiązuje przy używaniu vector :: iterator zamiast wskaźnika do wektora. :)Odpowiedzi:
Zostało to pominięte w normie C ++ 98, ale później dodane jako część TR. Nadchodzący standard C ++ 0x będzie oczywiście zawierał to wymaganie.
Od n2798 (wersja robocza C ++ 0x):
źródło
std::vector
są ciągłe. Np .: wstd::vector<std::vector<int>> v
elementachv[0]
,v[1]
... następnie są przechowywane w pamięci, ale elementv[0].back()
iv[1].front()
nie są gwarancją.Jak wskazywały inne odpowiedzi, zawartość wektora jest gwarantowana jako ciągła (z wyjątkiem dziwności boola).
Komentarz, który chciałem dodać, jest taki, że jeśli wykonasz wstawienie lub usunięcie w wektorze, co może spowodować ponowne przydzielenie wektora jego pamięci, spowoduje to unieważnienie wszystkich zapisanych wskaźników i iteratorów.
źródło
W rzeczywistości standard gwarantuje, że a
vector
jest ciągły w pamięci i&a[0]
może zostać przekazany doC
funkcji, która oczekuje tablicy.Wyjątkiem od tej reguły jest to,
vector<bool>
że używa tylko jednego bitu na,bool
więc chociaż ma pamięć ciągłą, nie może być używany jakobool*
(jest to powszechnie uważane za fałszywą optymalizację i błąd).BTW, dlaczego nie używasz iteratorów? Po to są.
źródło
Jak już powiedzieli inni,
vector
wewnętrznie używa ciągłej tablicy obiektów. Wskaźniki do tej tablicy powinny być traktowane jako nieprawidłowe, jeśli jakakolwiek funkcja składowa niebędąca stałą jest nazywana IIRC.Jest jednak wyjątek !!
vector<bool>
ma wyspecjalizowaną implementację zaprojektowaną w celu zaoszczędzenia miejsca, dzięki czemu każdy bool używa tylko jednego bitu. Podstawowa tablica nie jest ciągłą tablicą bool, a arytmetyka tablicyvector<bool>
nie działa takvector<T>
, jak powinna.(Przypuszczam, że jest to również możliwe, że może to dotyczyć dowolnej specjalizacji wektora, ponieważ zawsze możemy zaimplementować nową.
std::vector<bool>
Jest to jednak jedyna, błąd, standardowa specjalizacja, na której prosta arytmetyka wskaźnikowa nie będzie działać.)źródło
std::vector
, a wszystkie inne wektory muszą korzystać z ciągłego magazynu. Dlategostd::vector<bool>
jest (na szczęście) jedynym standardowym wektorem, który jest dziwny. (Jestem przekonany, że ta specjalizacja powinna zostać wycofana i zastąpiona np. Astd::dynamic_bitset
o podobnej funkcjonalności. To nie jest zła struktura danych, to po prostu nie jest wektor.)Znalazłem ten wątek, ponieważ mam przypadek użycia, w którym wektory korzystające z pamięci ciągłej są zaletą.
Uczę się używać obiektów bufora wierzchołków w OpenGL. Utworzyłem klasę opakowującą zawierającą logikę bufora, więc wszystko, co muszę zrobić, to przekazać tablicę wartości zmiennoprzecinkowych i kilka wartości konfiguracyjnych, aby utworzyć bufor. Chcę mieć możliwość wygenerowania buforu z funkcji na podstawie danych wejściowych użytkownika, więc długość nie jest znana w czasie kompilacji. Zrobienie czegoś takiego byłoby najłatwiejszym rozwiązaniem:
Teraz mogę przekazać elementy pływające wektora jako tablicę do funkcji związanych z buforem OpenGL. Eliminuje to również konieczność określania długości tablicy przez sizeof.
Jest to o wiele lepsze niż przydzielanie ogromnej tablicy do przechowywania pływaków i nadzieja, że zrobiłem ją wystarczająco dużą, lub tworzenie własnej dynamicznej tablicy z ciągłą pamięcią.
źródło
v
a nie dov
siebie? ponieważv
samo przejście spowoduje wykonanie kopii wewnątrz funkcji, która przestanie istnieć po zakończeniu funkcji. Tak więc wpychasz coś na wektor tylko po to, aby usunąć wektor po zakończeniu funkcji.cplusplus.com:
źródło
Tak, elementy std :: vector na pewno są ciągłe.
źródło