Czy jest zagwarantowane, że std::vector
przesuwa tylko swoje dane, gdy size()==capacity()
i wywołuje push_back()
lub emplace_back()
, czy może to zrobić również w inny sposób?Czy std :: vector przenosi dane na inny adres w emplace_back(), mimo że nadal nie ma wolnego miejsca w zależności od pojemności()?
Odpowiedz
Opis normy nie jest wystarczająco jasny.
$ 23.3.6.5 wektorowe modyfikatory [vector.modifiers]:
Uwagi: Powoduje realokacji jeśli nowy rozmiar jest większy niż stary pojemności. Jeśli nie nastąpi żadna realokacja, wszystkie iteratory i odwołania przed punktem wstawiania pozostają poprawne.
Więc kiedy dodać elementy do std::vector
realokacji na pewno stanie, gdy nowy rozmiar jest większy niż wydajności prądowej, ale nie mówi realokacja nie stanie, nawet jeśli nowa wielkość jest mniejsza lub równa wydajności prądowej . W każdym razie, jeśli realokacja nie nastąpi, wszystkie iteratory i odwołania do elementów przed punktem wstawienia muszą pozostać ważne, oznacza to, że dane nie zostaną przeniesione.
To samo dotyczy insert()
, emplace_back()
, emplace()
i push_back()
.
Cytat cppreference.com tylko jako punkt odniesienia:
Jeśli nowy
size()
jest większa niżcapacity()
wtedy wszystkie iteratory i odniesienia (w tym iteracyjnej past-the-end) są unieważniane. W przeciwnym razie unieważniany jest tylko iterator z ostatniej chwili.
Specyfikacja jest nieco pośrednia. capacity
jest określona jako:
size_type capacity() const noexcept;
Returns: łączna liczba elementów, że wektor może przechowywać bez konieczności realokacji.
Druga część pochodzi z reserve
:
reserve(size_type n);
Uwagi: Realokacja unieważnia wszystkie odniesienia, wskaźniki i iteratory odnoszące się do elementów w sekwencji. Nie nastąpi ponowne przydzielanie podczas wstawiania po wywołaniu do
reserve()
do momentu, w którym wstawienie spowodowałoby zwiększenie rozmiaru wektora o wartość większą niż wartośćcapacity()
.
Z tego można wywnioskować, że jeśli rozmiar jest mniejszy niż pojemność, wstawienie nie powoduje realokacji.
Nie ma pojedynczego, bezpośredniego stwierdzenia, że wektor nie przeniesie się, jeśli jest wolna pojemność i użytkownik nie nazwał jednoznacznie reserve
. Jednakże, nie są generalnie wymagane pojemnik [container.requirements.general]
O ile nie zaznaczono inaczej (bezpośrednio lub poprzez określenie funkcji w odniesieniu do innych funkcji), wywoływanie funkcji składowej pojemnik lub pojemnik przechodząc jako argument funkcji bibliotecznej nie unieważnia iteratorów ani nie zmienia wartości obiektów w tym kontenerze.
Wreszcie mamy opis skutków wstawienia:
[insert/emplace_back/push_back:]
Uwagi: Powoduje realokacji jeśli nowy rozmiar jest większy niż stary pojemności. Jeśli nie nastąpi żadna realokacja, wszystkie iteratory i odwołania przed punktem wstawienia zachowują ważność.
Łączenie wszystkich razem: O ile nie określono inaczej, wywoływanie funkcji składowej nie powoduje unieważnienia iteratorów. Realokacja unieważnia iteratory (opisane powyżej jako część reserve
), więc jeśli nie określono inaczej, wywoływanie funkcji składowej, a w szczególności wstawiania, nie powoduje ponownego przydzielenia, Jedna z takich nadpisań podana jest dla przypadku, w którym nowy rozmiar przekracza bieżący Pojemność.
Wygląda jak inny pod określonym zachowaniem. – NathanOliver
@NathanOliver: Właściwie wszystko jest w porządku, tylko trochę rozłożone. Zobacz aktualizację. –
@KerrekSB Porozmawiaj o konieczności wspólnego łączenia odpowiedzi :) Niestety, nie mogę cię powtórzyć. Dziękuję za poświęcony czas i wysiłek, aby wszystko to zmylić. – NathanOliver
@KerrekSB Czy uważasz, że opis na cppreference nie jest dokładny? (Powinien być naprawiony?) – songyuanyao
Nie, jestem całkowicie przekonany, że celem jest zdolność do kontrolowania realokacji w obie strony. To tylko trochę niedbałe sformułowanie. Byłoby to obłędnie inaczej, i prawdopodobnie istnieje wiele prawdziwego kodu, który zależy od tego zachowania. –
W rzeczywistości specyfikacja jest kompletna i hermetyczna, rozłożona jest na kilka sekcji. Zobacz moją zaktualizowaną odpowiedź. –