Większość implementacji std::string
(w tym GCC) stosuje optymalizację małych ciągów. Na przykład. dyskutuje o tym answer.Nie ma optymalizacji małych ciągów za pomocą gcc?
Dzisiaj postanowiłem sprawdzić, w którym punkcie napis w skompilowanym przeze mnie kodzie zostanie przeniesiony do sterty. Ku mojemu zaskoczeniu mój kod testowy zdaje się wskazywać, że w ogóle nie ma optymalizacji małych napisów!
Kod:
#include <iostream>
#include <string>
using std::cout;
using std::endl;
int main(int argc, char* argv[]) {
std::string s;
cout << "capacity: " << s.capacity() << endl;
cout << (void*)s.c_str() << " | " << s << endl;
for (int i=0; i<33; ++i) {
s += 'a';
cout << (void*)s.c_str() << " | " << s << endl;
}
}
Wyjście g++ test.cc && ./a.out
jest
capacity: 0
0x7fe405f6afb8 |
0x7b0c38 | a
0x7b0c68 | aa
0x7b0c38 | aaa
0x7b0c38 | aaaa
0x7b0c68 | aaaaa
0x7b0c68 | aaaaaa
0x7b0c68 | aaaaaaa
0x7b0c68 | aaaaaaaa
0x7b0c98 | aaaaaaaaa
0x7b0c98 | aaaaaaaaaa
0x7b0c98 | aaaaaaaaaaa
0x7b0c98 | aaaaaaaaaaaa
0x7b0c98 | aaaaaaaaaaaaa
0x7b0c98 | aaaaaaaaaaaaaa
0x7b0c98 | aaaaaaaaaaaaaaa
0x7b0c98 | aaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0cd8 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0x7b0d28 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Zgaduję, że większe pierwszy wskaźnik, tj 0x7fe405f6afb8
jest wskaźnik stosu, a pozostałe z nich wskazują na stercie . Uruchomienie tego wiele razy daje identyczne wyniki, w tym sensie, że pierwszy adres jest zawsze duży, a pozostałe są mniejsze; dokładne wartości zazwyczaj różnią się. Mniejsze adresy zawsze są zgodne ze standardową mocą 2 schematu alokacji, np. 0x7b0c38
figuruje raz, potem 0x7b0c68
figuruje raz, potem 0x7b0c38
dwa razy, a następnie 0x7b0c68
4 razy, potem 0x7b0c98
8 razy itd
Po przeczytaniu odpowiedzi Howarda, przy użyciu maszyny do 64bit, spodziewałem się zobaczyć ten sam adres drukowane dla pierwszych 22 znaków, a tylko wtedy, aby zobaczyć, jak się zmienia.
Czy brakuje mi czegoś?
także, co ciekawe, jeśli skompilować z -O
(na każdym poziomie), mam stałą małą wartość wskaźnika 0x6021f8
w pierwszym przypadku, zamiast dużej wartości, a to 0x6021f8
nie zmienia się niezależnie od tego, ile razy Uruchomę program.
Wyjście g++ -v
:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/foo/bar/gcc-6.2.0/gcc/libexec/gcc/x86_64-redhat-linux/6.2.0/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../gcc-6.2.0/configure --prefix=/foo/bar/gcc-6.2.0/gcc --build=x86_64-redhat-linux --disable-multilib --enable-languages=c,c++,fortran --with-default-libstdcxx-abi=gcc4-compatible --enable-bootstrap --enable-threads=posix --with-long-double-128 --enable-long-long --enable-lto --enable-__cxa_atexit --enable-gnu-unique-object --with-system-zlib --enable-gold
Thread model: posix
gcc version 6.2.0 (GCC)
'--with-default-libstdcxx-abi = kompatybilny z gcc4" –
@ T.C. Naprawdę? 'gcc4' nie miał małej optymalizacji łańcucha? – SU3
Pomyślałem, że przypomniałem sobie, że małą optymalizację napisów należy umieścić (z powrotem) w języku – xaxxon