2015-12-19 19 views
12

Piszę kod C++ 11, który sprawia, że ​​założenia dotyczące natury std::string są prawidłowe, ale reprezentują zachowanie, które zostało zmienione w C + +11. Wcześniejsza implementacja libstdC++ była zgodna z wymaganiami 98/03, ale nie z bardziej restrykcyjnymi wymaganiami C++ 11.Sprawdź, czy wersja libstdC++ używa zgodnego z C++ 11 std :: string

Jak rozumiem, libstdC++ naprawił problemy związane z basic_string. Problem polega na tym, że istnieje wiele wersji biblioteki, z których korzystają ludzie, które nie implementują tej poprawki. A mój kod może po cichu zawieść na wiele nieprzyjemnych sposobów.

Chciałbym mieć pożar static_assert, jeśli użytkownik spróbuje skompilować moją bibliotekę przeciw niezgodnym wersjom libstdC++. Jak wykryć wersję i, co równie ważne, której wersji powinienem szukać?

+1

Czy możesz wyrazić swoje przypuszczenia? –

+1

Uważam, że jest to wymagane nawet w C++ 03. COW powinien zachować tę właściwość. – Puppy

+0

@Puppy: Przepraszam, powiedziałem to źle. Lepiej po prostu [patrz tutaj] (http://stackoverflow.com/a/29199733/734069). Coś w tym stylu. –

Odpowiedz

9

Nowa wersja C++ 11 std::string została wprowadzona z nowym (podwójnym) ABI w GCC 5 (Runtime Library Section of the changelog).

Makro _GLIBCXX_USE_CXX11_ABI decyduje, czy stare czy nowe ABI jest używany, więc po prostu sprawdzić go:

#if _GLIBCXX_USE_CXX11_ABI 

Oczywiście, które jest specyficzne dla libstdC++ tylko.

5
#include <string> 

static_assert(sizeof(std::string) != sizeof(void*), "using ref-counted string"); 

int 
main() 
{ 
} 

Demo: http://melpon.org/wandbox/permlink/P8LB79Cy6ASZlKuV

Test ten wykorzystuje wewnętrzne funkcjonowanie wszystkich znanych std :: lib implementacjach std::string i realizacji GCC w szczególności.

refcounted gcc string składa się z pojedynczego wskaźnika do dynamicznie przydzielonej struktury, która przechowuje rozmiar, pojemność, liczbę referencji i dane ciągu. Scott Meyers robi miłe podsumowanie implementacji łańcuchów w Effective STL, które były dokładne w 2001 roku. Wierzę (mogłem się mylić), że "implementacja C" w pozycji 15 tej książki to std :: string gcc.

W przypadku implementacji krótkich łańcuchów (prawie nakazanych przez C++ 11), string nie może już składać się z pojedynczego wskaźnika na stosie. Implementacja Scotta D to nasze pierwsze spojrzenie na krótką implementację z tamtej epoki. To jest VS/Dinkumware string. Sam plik sizeof(string) będzie zawierał bufor danych do przechowywania danych ciągów bez alokacji.

Można uzyskać uchwyt na co różne implementacje robią z tego krótkiego programu:

#include <iostream> 
#include <string> 

int 
main() 
{ 
    std::string s; 
    std::cout << "word size is   " << sizeof(void*)/sizeof(char) << '\n'; 
    std::cout << "sizeof string is  " << sizeof(s) << '\n'; 
    std::cout << "short string buffer is " << s.capacity() << '\n'; 
} 

ten wypisuje rozmiar tekstu, zazwyczaj 4 lub 8 (32-bitowy/64-bitowy) co najmniej jedną implementację (libC++) zmienia swoją charakterystykę na tej funkcji sprzętowej. Następnie wypisze sizeof(string), która będzie wielokrotnością rozmiaru słowa, a następnie capacity() pustego string, który będzie wielkością bufora krótkiego łańcucha, jeśli istnieje.

Oto nieco niekompletny przegląd:

gcc/libstdc++ 4.8 

word size is   8 
sizeof string is  8 
short string buffer is 0 

gcc/libstdc++ 5.2 

word size is   8 
sizeof string is  32 
short string buffer is 15 

clang/libc++ -arch i386 OS X 

word size is   4 
sizeof string is  12 
short string buffer is 10 

clang/libc++ -arch x86_64 OS X 

word size is   8 
sizeof string is  24 
short string buffer is 22 

VS-2015 

word size is   4 
sizeof string is  24 
short string buffer is 15 

W tej ankiecie tylko gcc/libstdC++ 4.8 najwyraźniej nie używa optymalizacji krótkich łańcuchów. I tylko gcc/libstdC++ 4.8 ma sizeof(string) == 1 word. I to jest w rzeczywistości jedyna implementacja w tej ankiecie, która wykorzystuje liczenie odwołań.

Podsumowując, ten test dla libstdC++ 's std::string nie jest przenośny. Ale według specyfikacji nie musi tak być. Możemy skorzystać ze znanej historii rozwoju gcc w tym obszarze. Spec (pytanie) mówi, że musi działać tylko na libstdC++ gcc.

+0

Czy możesz krótko wyjaśnić, dlaczego to zrobi? Czy łańcuchy COW mają tylko jeden element danych void * (prywatny) i oczywiście brak funkcji wirtualnych? – vsoftco

+1

OK, gotowe ....... –

+0

Dzięki, wielkie wyjaśnienie. – vsoftco