(Nie jest to samo w sobie programowanie gier, ale jestem pewien, że jeśli zapytam o to SO, powiedzą mi, żebym nie przedwcześnie optymalizował, chociaż historia mówi nam, że każda duża gra kończy się martwiąc o te rzeczy.)
Czy jest gdzieś dokument, który podsumowuje różnice w wydajności, a zwłaszcza w użyciu pamięci, między różnymi implementacjami biblioteki standardowej C ++? Szczegóły niektórych implementacji są chronione przez NDA, ale porównanie nawet STLport vs. libstdc ++ vs. libc ++ vs. MSVC / Dinkumware (vs. EASTL?) Wydaje się niezwykle przydatne.
W szczególności szukam odpowiedzi na pytania takie jak:
- Ile narzutu pamięci wiąże się ze standardowymi kontenerami?
- Jakie kontenery, jeśli istnieją, dokonują alokacji dynamicznych jedynie poprzez deklarację?
- Czy std :: string wykonuje kopiowanie przy zapisie? Optymalizacja krótkiego ciągu? Liny
- Czy std :: deque używa bufora pierścieniowego, czy to bzdura?
deque
zawsze był implementowany w STL z wektorem.Odpowiedzi:
W przypadku, gdy nie znajdziesz takiej tabeli porównawczej, alternatywą jest wstrzyknięcie własnego alokatora do danych klas STL i dodanie logowania.
Testowana przeze mnie implementacja (VC 8.0) nie korzysta z alokacji pamięci, tylko deklarując ciąg / wektor / deque, ale robi to na liście i mapowaniu. Ciąg ma optymalizację krótkiego ciągu, ponieważ dodanie 3 znaków nie uruchomiło przydziału. Dane wyjściowe są dodawane poniżej kodu.
Do tej pory testowane VC8 i STLPort 5.2, oto porównanie (zawarte w teście: ciąg, wektor, deque, lista, mapa)
Łańcuch wyjściowy VC8 / wektor / deque / list / map:
STLPort 5.2. wyjście skompilowane z VC8
Wyniki EASTL , brak dostępnych danych
źródło
std::string
nie kopiuje przy zapisie. CoW była kiedyś optymalizacją, ale jak tylko wiele wątków wejdzie na obraz, jest to poza pesymizacją - może spowolnić kod z powodu ogromnych czynników. Szkoda, że C ++ 0x Standard aktywnie zakazuje go jako strategii implementacji. Nie tylko to, ale permisywnośćstd::string
eliminowania zmiennych iteratorów i odwołań do znaków oznacza, że „pisz”std::string
oznacza prawie każdą operację.Wydaje mi się, że optymalizacja krótkich ciągów znaków to około 6 znaków lub coś w tym regionie. Liny nie są dozwolone -
std::string
musi przechowywać ciągłą pamięć dlac_str()
funkcji. Technicznie rzecz biorąc, możesz utrzymywać zarówno ciągły sznurek, jak i linę w tej samej klasie, ale nikt tego nigdy nie zrobił. Co więcej, z tego, co wiem o linach, uczynienie ich bezpiecznymi do manipulowania nicią byłoby niezwykle powolne - może tak złe lub gorsze niż CoW.Żaden kontener nie dokonuje alokacji pamięci, ponieważ został zadeklarowany w nowoczesnych STL. Kontenery oparte na węzłach, takie jak lista i mapa, służyły do tego, ale teraz mają wbudowaną optymalizację końca i nie potrzebują jej. Często wykonuje się optymalizację zwaną „swaptimization”, w której zamieniasz pusty pojemnik. Rozważać:
Oczywiście w C ++ 0x jest to nadmiarowe, ale w C ++ 03 wtedy, gdy było to powszechnie używane, jeśli MahVariable przydziela pamięć na deklarację, zmniejsza to efektywność. Wiem na pewno, że zostało to wykorzystane do szybszych realokacji kontenerów, jak
vector
w MSVC9 STL, co wyeliminowało potrzebę kopiowania elementów.deque
korzysta z czegoś, co określa się jako rozwiniętą listę połączoną Zasadniczo jest to lista tablic, zwykle w węźle o stałej wielkości. Jako taki, do większości zastosowań, zachowuje zalety obu struktur danych - ciągły dostęp i amortyzowane usuwanie O (1) oraz możliwość dodawania zarówno z przodu, jak iz tyłu oraz lepsze unieważnienie iteratora niżvector
.deque
nigdy nie może zostać zaimplementowany przez wektor ze względu na złożoność algorytmu i gwarancje unieważnienia iteratora.Ile narzutu pamięci jest związane? Cóż, szczerze mówiąc, to trochę bezwartościowe pytanie. Kontenery STL zostały zaprojektowane tak, aby były wydajne, a jeśli powielasz ich funkcjonalność, albo uzyskasz coś gorszego, albo w tym samym miejscu. Znając ich podstawowe struktury danych, możesz poznać narzut pamięci, którego używają, dają lub zabierają, i będzie to więcej niż tylko z dobrego powodu, takiego jak optymalizacja małych ciągów.
źródło
std::string
tak było. Nie musisz do tego używać najnowszych i najlepszych implementacji STL. msdn.microsoft.com/en-us/library/22a9t119.aspx mówi „Jeśli element zostanie wstawiony z przodu, wszystkie odniesienia pozostaną ważne”. Nie wiesz, jak zamierzasz wdrożyć to z okrągłym buforem, ponieważ będziesz musiał zmienić rozmiar, gdy się zapełni.Jeśli to naprawdę twoje pytanie (które jest z całą pewnością nie jest tym, co powiedziałeś w tekście pytania, które zakończyło się 4 pytaniami, z których żadne nie zadawało pytania, gdzie możesz znaleźć zasób), odpowiedź brzmi po prostu:
Nie ma jednego
Większość programistów C ++ nie musi przejmować się zbytnio standardowymi strukturami bibliotek, ich wydajnością w pamięci podręcznej (co jest wysoce zależna od kompilatora), czy czymś podobnym. Nie wspominając o tym, że zazwyczaj nie można wybrać standardowej implementacji biblioteki; korzystasz z kompilatora. Więc nawet jeśli robi to nieprzyjemne rzeczy, opcje alternatyw są ograniczone.
Są oczywiście programiści, którzy dbają o tego rodzaju rzeczy. Ale wszyscy dawno przysięgali, że korzystają ze standardowej biblioteki.
Więc masz jedną grupę programistów, których po prostu nie obchodzi. I kolejna grupa programistów, którzy by się przejmowali, gdyby go używali, ale ponieważ go nie używają, nie obchodzi ich to. Ponieważ nikt się tym nie przejmuje, nie ma prawdziwych informacji na ten temat. Istnieją nieformalne łaty informacji tu i tam (Efektywne C ++ ma sekcję na temat implementacji std :: string i ogromnych różnic między nimi), ale nic kompleksowego. I na pewno nic nie było na bieżąco.
źródło