Is it possible to initialize string with specific capacity?



  • Hi,

    ich guck mir gerade C++11 und C++14 Sachen an und Frage mich im Hinblick auf die neuen Init_lists ob es eine Möglichkeit gibt einen leeren String bereits mit der benötigten Capacity zu erstellen?

    Im Moment schreibe ich:

    std::string mystr;
    mystr.reserve(my_value);
    

    Gibt es eine Möglichkeit mir die zweite Zeile zu sparen und mystr bereits mit korrekter Capacity zu erstellen.

    Es geht nur um Capacity ich möchte nicht, dass in dem string irgendwas drinnensteht.
    BIs jetzt habe ich in den init_lists nur value Initialisierung aber nicht capacity Initialisierung gesehen.


  • Mod

    Noe. Mach's so wie jetzt auch, was ist an dem Zweizeiler verkehrt?



  • Arcoth schrieb:

    Noe. Mach's so wie jetzt auch, was ist an dem Zweizeiler verkehrt?

    Gar nix, aber es wäre so schön gewesen aus dem Zweizeiler einen Einzeiler zu machen. 😉

    Mich hat das reserve immer gestört, weil es spricht eigentlich nichts dagen das schon bei der Konstruktion des strings zu machen.

    Würde eine unnötige Allokierung sparen und 1 Zeile ist besser als 2. 🙂


  • Mod

    std__string schrieb:

    Würde eine unnötige Allokierung sparen und 1 Zeile ist besser als 2. 🙂

    Der String allokiert keine 0 Bytes.



  • Da, eine Zeile: ein Statement:

    std::string mystr = [my_value] { std::string mystr; mystr.reserve(my_value); return mystr; }();
    


  • TyRoXx schrieb:

    Da, eine Zeile:

    std::string mystr = [my_value] { std::string mystr; mystr.reserve(my_value); return mystr; }();
    

    Da, eine Zeile:

    std::string mystr; mystr.reserve(my_value);
    


  • Tut mir leid, dass ich jetzt so blöd frage, aber was bringt das

    myStr.reserve(myVal);
    


  • template <typename T, typename... Args>
    T reserved(std::size_t n, Args&&... args) {
      auto container = T(std::forward<Args>(args)...);
      container.reserve(n);
      return container;
    }
    
    auto mystr = reserved<std::string>(my_value);
    


  • SeppJ schrieb:

    Der String allokiert keine 0 Bytes.

    Das verstehe ich jetzt nicht ganz.

    Wenn ich einen string erstelle mit:

    std::string mystr;
    

    und anschließend die Capacity Abfrage bekomme ich 15 zurück.

    Das bedeutet doch, dass er intern defaultmäßig ein Array der Größe 15 allokiert hat oder nicht?

    Wenn ich mich in Debug durch das String Objekt bewege sehe ich auch ein char Array der Größe 16 oder gucke ich falsch?


  • Mod

    std_string schrieb:

    std::string mystr;
    

    und anschließend die Capacity Abfrage bekomme ich 15 zurück.

    15 klingt verdächtig nach 2-4 Pointer minus 1.



  • SeppJ schrieb:

    std_string schrieb:

    std::string mystr;
    

    und anschließend die Capacity Abfrage bekomme ich 15 zurück.

    15 klingt verdächtig nach 2-4 Pointer minus 1.

    Entschuldige, aber ich kann mit deiner Äußerung nicht soviel anfangen, bzw. verstehe nicht auf was du hinaus willst.

    Wenn ich mir im Debug mode mein String Objekt ansehe, sehe ich eine Capacity von 15, wenn ich in die [Raw View] reingehe, sehe ich nach einigen Hierachieebenen einen char pointer der anscheinend ins Leere zeigt und ein _Alias char Array[16], dass an Position 0 mit '\0' und an Positionen 1-15 mit -52 initialisiert wurde.

    Der einzige Unterschied im Release Mode sind die Werte die im Array stehen, aber an Position [0] steht anscheinend immer ein '\0' was darauf hindeutet, dass dieses Array wirklich existiert bzw. der Speicher vom String Objekt wirklich allokiert wurde, oder nicht?



  • MSVC hält Strings bis zur Länge 15(+'\0') direkt im Objekt selber. Erst wenn längere Strings benötigt werden wird im Freispeicher alloziert.
    Die anderen Compiler dürften ähnliches machen.

    Nennt sich "Short String Optimization"(SSO).



  • Caligulaminus schrieb:

    MSVC hält Strings bis zur Länge 15(+'\0') direkt im Objekt selber. Erst wenn längere Strings benötigt werden wird im Freispeicher alloziert.
    Die anderen Compiler dürften ähnliches machen.

    Nennt sich "Short String Optimization"(SSO).

    😮 Ok, das wusste ich nicht. 😮

    Interessant, das bedeutet, dass jedes String Objekt ein char[15] Array mit sich herumschleppt auch, wenn es bei size > 16 überhaupt nicht mehr benötigt wird.

    Ich habe gerade bei mir MSVC2013 geguckt und bei mir ist es wirklich so.

    Ich sehe bei size > 16 den Char Pointer und deep in der Hierachie , dass nicht mehr benutzte char array.



  • std_string schrieb:

    Interessant, das bedeutet, dass jedes String Objekt ein char[15] Array mit sich herumschleppt auch, wenn es bei size > 16 überhaupt nicht mehr benötigt wird.

    Wenn Freispeicher verwendet wird, wird der Platz des internen Arrays für Zeiger und Kapazität(size_t oder auch ein Zeiger) verwendet. Unter x64 wird so nichts vergeudet. Unter x64 gehen - glaube ich - 8 Byte verloren, ja. Aber das ist ein kleiner Preis für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).


  • Mod

    Caligulaminus schrieb:

    für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).

    Da gibt es übrigens keinen Interpretationsspielraum. std::string ist die Instanzierung des basic_string-Templates mit char als Datentyp und dem Defaultallokator als Allokator. Und dieser läuft letztlich auf ::operator new hinaus.



  • SeppJ schrieb:

    Caligulaminus schrieb:

    für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).

    Da gibt es übrigens keinen Interpretationsspielraum. std::string ist die Instanzierung des basic_string-Templates mit char als Datentyp und dem Defaultallokator als Allokator. Und dieser läuft letztlich auf ::operator new hinaus.

    Wie ist das denn genau definiert? Müsste ja so sein, dass es ein implementationsdefiniertes, festes N geben muss, sodass gilt: ( size() >= N) impliziert ( data() kommt vom Allocator). Das würde dann die SSO erlauben.


  • Mod

    TyRoXx schrieb:

    SeppJ schrieb:

    Caligulaminus schrieb:

    für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).

    Da gibt es übrigens keinen Interpretationsspielraum. std::string ist die Instanzierung des basic_string-Templates mit char als Datentyp und dem Defaultallokator als Allokator. Und dieser läuft letztlich auf ::operator new hinaus.

    Wie ist das denn genau definiert? Müsste ja so sein, dass es ein implementationsdefiniertes, festes N geben muss, sodass gilt: ( size() >= N) impliziert ( data() kommt vom Allocator). Das würde dann die SSO erlauben.

    as-if.
    Wird SSO überhaupt mit eigenen Allokatoren angewandt?



  • TyRoXx schrieb:

    SeppJ schrieb:

    Caligulaminus schrieb:

    für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).

    Da gibt es übrigens keinen Interpretationsspielraum. std::string ist die Instanzierung des basic_string-Templates mit char als Datentyp und dem Defaultallokator als Allokator. Und dieser läuft letztlich auf ::operator new hinaus.

    Wie ist das denn genau definiert? Müsste ja so sein, dass es ein implementationsdefiniertes, festes N geben muss, sodass gilt: ( size() >= N) impliziert ( data() kommt vom Allocator). Das würde dann die SSO erlauben.

    §21.4.1/4 schrieb:

    [...]Every object of type basic_string<charT,traits, Allocator> shall use an object of type Allocator to allocate and free storage for the contained charT objects as needed.



  • Nathan schrieb:

    §21.4.1/4 schrieb:

    [...]Every object of type basic_string<charT,traits, Allocator> shall use an object of type Allocator to allocate and free storage for the contained charT objects as needed.

    Das verbietet SSO. Und jetzt?


  • Mod

    TyRoXx schrieb:

    SeppJ schrieb:

    Caligulaminus schrieb:

    für ein gespartes new (oder wie dein std::string auch immer den Speicher holt).

    Da gibt es übrigens keinen Interpretationsspielraum. std::string ist die Instanzierung des basic_string-Templates mit char als Datentyp und dem Defaultallokator als Allokator. Und dieser läuft letztlich auf ::operator new hinaus.

    Wie ist das denn genau definiert? Müsste ja so sein, dass es ein implementationsdefiniertes, festes N geben muss, sodass gilt: ( size() >= N) impliziert ( data() kommt vom Allocator). Das würde dann die SSO erlauben.

    Das folgt schon aus den Komplexitätsgarantien, z.B. für swap.
    SSO ist im Übrigen für normale Container nicht zulässig, da dort Iteratoren auf Elemente (gilt nicht für end) bei swap stabil bleiben müssen.


Anmelden zum Antworten