Czy do pliku zapisywany jest string czy tylko adres do niego?

0
struct MyStruct{
    uint64_t a;
    uint64_t b;
    std::string s;
};

MyStruct obiekt;
    obiekt.a = 11;
    obiekt.b = 22;
    obiekt.s = "The quick brown fox jumps over the lazy dog";
    std::ofstream plikOUT;
    plikOUT.open("out.bin", std::ios::binary | std::ios::out);
    plikOUT.write((const char*)&obiekt, sizeof(MyStruct));
    plikOUT.close();


Pytanie początkującego. Czy do pliku jest zapisywany cały string, czy tylko adres do tego stringa? Jeśli adres, to co z jego ważnością?

4

@didzni:

Ani jedno, ani drugie w sensie dokladnym.
Zapisywana jest wewnętzrna struktura obiektu std::string, taka jaką tworca biblioteki std (kompilatora) przyjął
Być może tak jest długośc, być może jest adres, może jakies flagi bitowe itd...
Być może jeszcze inny ulep (niekiedy były stospowany tricki, odmienna implementacja dla "długich" stringów, odmienna dla "krótkich")

didzni napisał(a):

Jeśli adres, to co z jego ważnością?

masz dobre myślenie. Zapisany adres jest de facto nieprzydatny.

To, co byś chciał uzyskać (JAK MNIEMAM) nazywa się serializacja, choć w C++ nie ma nad tym jakiejś ukierunkowanej refleksji

1

To jest undefined behavior.
MOże wydawać sie działać, bo wszystkie ważne kompilatory implementują Small String Optimalization (SSO).
Użyj napisu dłużego niż std::string{}.capacity() (na gcc/clang 15) a będzie to oczywiste.

0

Chociaż wygląda na sprytne to bardzo paskudne rozwiązanie. Weź w osobnej funkcji zbuduj osobnego stringa składającego się z elementów tej struktury i na spokojnie go zapisz do pliku.

Możesz nawet iterowac po memberach struktury używając np boost fusion. Będzie to skalowalne, ale nie jest to idealne rozwiązanie.

1

Jeżeli już boost to masz tam wprost serialization

0

Binarna i niebinarna serializacja w C++ jest podchwytliwa i jeśli nie pisze się tego dla zabawy lub nauki, powinno sięgać się po biblioteki jak alpaca, nlohmann/json czy coś z boost które te rzeczy zrobią z automatu będąc odpornymi na większość błędów :P

W obecnym kodzie zapisujesz reprezentację bajtów MyStruct w pamięci do pliku - czyli dwie zmienne typu uint64_t oraz wewnętrzną reprezentację std::string która składa się ze wskaźnika na Twój łańcuch znakowy i innych duperełek które std::string wykorzystuje pod spodem do poprawnego działania. Żadnego łańcucha znaków w środku nie znajdziesz.

Pomijam już kwestie wrzucania pustych bajtów przez kompilator do struktury oraz różnic w niektórych typach w zależności od architektury (size_t itp.).

Jeśli Twoim celem było zapisanie tego do pliku z możliwością wiernego odtworzenia, trzeba zserializować każdą zmienną oddzielnie. Podobnie z odczytem.
Jak to zrobić poprawnie, to już zupełnie inna sprawa zależna od zmiennej, w przypadku std::string wystarczy rozmiar i ciąg znaków.

https://godbolt.org/z/evsrK1P5j

1 użytkowników online, w tym zalogowanych: 0, gości: 1