Mam ten problem przed przyjacielem

#include <string>
#include <vector>
#include <iostream>

void riddle(std::string input)
{
    auto strings = std::vector<std::string>{};
    strings.push_back(input);
    auto raw = strings[0].c_str();

    strings.emplace_back("dummy");

    std::cout << raw << "\n";
}

int main()
{
    riddle("Hello world of!"); // Why does this print garbage?
    //riddle("Always look at the bright side of life!"); // And why doesn't this?

    std::cin.get();
}

Moją pierwszą obserwacją jest to, że funkcja riddle() nie wytworzy śmieci, gdy liczba słów przeszła do input jest więcej niż 3 słowa. Nadal próbuję zobaczyć, dlaczego nie powiedzie się na pierwszym przypadku, a nie dla drugiego przypadku. W każdym razie pomyślałem, że to fajnie się dzielić.

0
Wolfy 21 luty 2019, 06:45

2 odpowiedzi

Najlepsza odpowiedź

Jest to niezdefiniowane zachowanie (UB), co oznacza, że wszystko może się wydarzyć, w tym działanie kodu. Jest UB, ponieważ emplace_back unieważnia wszystkie wskaźniki do obiektów w wektorze. Dzieje się tak, ponieważ wektor może być przeterokowany (który najwyraźniej jest).

Pierwszy przypadek UB "nie działa" z powodu krótkiej optymalizacji string (SSO). Ze względu na SSO surowy wskaźnik wskazuje na pamięć bezpośrednio przydzieloną przez wektor, który jest tracony po realokacji.

Drugi przypadek UB "działa", ponieważ tekst łańcuchowy jest zbyt długi dla SSO i mieszka na niezależnym bloku pamięci. Podczas zmiany rozmiaru obiektów jest przenoszony z, przesuwając własność bloku pamięci tekstu do nowo utworzonego obiektu ciągów. Ponieważ blok pamięci po prostu zmienia własność, pozostaje ważny po emplace_back.

3
Michael Veksler 21 luty 2019, 04:44

std::string::c_str():

Wrócił wskaźnik może zostać unieważniony przez dalsze połączenia z innymi funkcjami członków, które modyfikują obiekt.


{X0}}:

Jeśli nastąpi realokacja, wszystkie zawierające elementy są modyfikowane.


Ponieważ nie ma sposobu, aby wiedzieć, czy reallokacja vector ma się wydarzyć podczas dzwonienia {X1}} Musisz założyć, że późniejsze użycie wcześniejszej wartości powrotu z {x2}} prowadzi do niezdefiniowanego zachowania.

Ponieważ niezdefiniowane zachowanie jest - niezdefiniowane - wszystko może się wydarzyć. Dlatego twój kod może wydawać się pracować lub może wydawać się niepowodzeniem. Jest w razie błędu.

2
Sid S 21 luty 2019, 05:47