char* als key einer std::map



  • Du kannst Pointer als Key verwenden. Das ist ja bei deinem Beispiel auch nicht das Problem, sondern ( wie du ja selbst festgstellt hast ) die Lebenszeit des Objekts, auf das der Pointer zeigt.
    Die Frage ist allerdings, warum man auf die Idee kommt, in einem C++ Programm char* statt std::string zumverwenden.



  • seldon schrieb:

    TravisG schrieb:

    Das Verhalten ist hier denke ich undefiniert. "Standardkonform" ist es damit natürlich immernoch (sonst würde es nicht kompilieren - es sei denn der Compiler compiled falsch).

    Das ist aber ein merkwürdiges Verständnis von "standardkonform".

    Macht er irgendetwas, dass dem Standard widerspricht? So verstehe ich das zumindest. Wenn alles nicht standardkonform ist, dass undefiniertes Verhalten erzeugt - na gut, dann ist das halt eine andere Definitionsmöglichkeit des Wortes.



  • Standardkonformes Verhalten heißt doch, dass es sich do verhält, wie der Standard es definiert. Wenn der Standard explizit sagt, dass er nichts definiert, gibts auch nichts, womit das Verhalten konform sein kann. Was man allerdings sagen kann ist, dass das Verhalten den Standard nicht verletzt - weil es eben auch nichts gitb, was man verletzen könnte in der Hinsicht.

    Dass der oben gezeigte Code undefiniertes Verhalten erzeugt, ist ja klar, allerdings ist er sehr einfach zu reparieren:

    struct cmp_map_key
    {
       bool operator()(char const* a, char const* b)
       {
           int res = strcmp(a,b);
           return res<0;
       }
    };
    
    int main()
    {
        map<char const*,int,cmp_map_key> m;
    
        {
            char const* str = "Test";
            m[str] = 777;
        } // key zeigt ja nun auf einen freigegebenen Speicherbereich.
    
        char const* str = "Test";
        cout << m[str];
    }
    

    Sobald man den Text nicht mehr unnötigerweise vom String-Literal in ein lokales Array kopieren lässt (unnötig weil nichts damit angestellt wird), ist das Programm völlig in Ordnung, weil ganz einfach die String-Literale selbst statische Lebenszeit haben, d.h. sie bleiben bis Programmende bestehen und damit bleiben auch die Pointer gültig.



  • pumuckl schrieb:

    Standardkonformes Verhalten heißt doch, dass es sich do verhält, wie der Standard es definiert. Wenn der Standard explizit sagt, dass er nichts definiert, gibts auch nichts, womit das Verhalten konform sein kann. Was man allerdings sagen kann ist, dass das Verhalten den Standard nicht verletzt - weil es eben auch nichts gitb, was man verletzen könnte in der Hinsicht.

    Dass der oben gezeigte Code undefiniertes Verhalten erzeugt, ist ja klar, allerdings ist er sehr einfach zu reparieren:

    struct cmp_map_key
    {
       bool operator()(char const* a, char const* b)
       {
           int res = strcmp(a,b);
           return res<0;
       }
    };
    
    int main()
    {
        map<char const*,int,cmp_map_key> m;
    
        {
            char const* str = "Test";
            m[str] = 777;
        } // key zeigt ja nun auf einen freigegebenen Speicherbereich.
    
        char const* str = "Test";
        cout << m[str];
    }
    

    Sobald man den Text nicht mehr unnötigerweise vom String-Literal in ein lokales Array kopieren lässt (unnötig weil nichts damit angestellt wird), ist das Programm völlig in Ordnung, weil ganz einfach die String-Literale selbst statische Lebenszeit haben, d.h. sie bleiben bis Programmende bestehen und damit bleiben auch die Pointer gültig.

    Ist es wirklich definiert, dass die gleichen Literale auch wirklich die selben sind?



  • TravisG schrieb:

    Ist es wirklich definiert, dass die gleichen Literale auch wirklich die selben sind?

    Nein. Das darf, muss aber nicht. Ist hier aber auch nicht wichtig, da ja nicht die Zeiger verglichen werden.



  • TravisG schrieb:

    Ist es wirklich definiert, dass die gleichen Literale auch wirklich die selben sind?

    Nein. Aber dafür hat er ja den eigenen Komparator geschrieben 🙂 Damit werden Pointer auf die gleichen Literale von der Map immer als äquivalent betrachtet. Dass der in der map gespeicherte Pointer aus Zeile 15/16 eventuell nicht den selben Wert hat wie der Pointer in Zeile 19/20 macht deshalb nichts.
    Dazu ist definiert, dass die Literale bis Programmende gültig bleiben, also passt das so.


  • Mod

    cooky451 schrieb:

    TravisG schrieb:

    Ist es wirklich definiert, dass die gleichen Literale auch wirklich die selben sind?

    Nein. Das darf, muss aber nicht. Ist hier aber auch nicht wichtig, da ja nicht die Zeiger verglichen werden.

    Genau genommen wäre ein direkter Vergleich der Zeiger wieder unspezifiziertes Verhalten, wenn sie nicht auf Objekte im selben Array zeigen. Funktioniert natürlich trotzdem auf allen modernen Maschinen, kann aber schiefgehen auf einfachen Architekturen.



  • SeppJ schrieb:

    Genau genommen wäre ein direkter Vergleich der Zeiger wieder unspezifiziertes Verhalten, wenn sie nicht auf Objekte im selben Array zeigen.

    Niemals. Wo soll das denn stehen?



  • SeppJ schrieb:

    Genau genommen wäre ein direkter Vergleich der Zeiger wieder unspezifiziertes Verhalten, wenn sie nicht auf Objekte im selben Array zeigen.

    Ganz genau genommen wäre das Weglassen des Komparators allerdings auch kein direkter Vergleich, sondern std::less, was wiederum für Pointer wohldefiniert ist, auch wenn sie nicht ins selbe Array zeigen, aus genau dem Grund 🙂

    cooky451 schrieb:

    Niemals. Wo soll das denn stehen?

    Steht im Standard, dass op< für Pointer nur in Arrays in Ordnung ist.



  • pumuckl schrieb:

    cooky451 schrieb:

    Niemals. Wo soll das denn stehen?

    Steht im Standard, dass op< für Pointer nur in Arrays in Ordnung ist.

    Hehe, jetzt habe ich es auch gefunden. Habe SeppJs unspezifiziert etwas voreilig als undefiniert abgetan. Interessant ist das aber trotzdem. Müssen ja lustige Maschinen sein, bei denen das nicht klappt.


  • Mod

    cooky451 schrieb:

    Müssen ja lustige Maschinen sein, bei denen das nicht klappt.

    Ja, echt exotisch diese 286er mit ihrem MS-DOS 🙂 .

    pumuckl schrieb:

    sondern std::less, was wiederum für Pointer wohldefiniert ist

    Irgendwie hatte ich das im Hinterkopf, aber ich konnte es nirgends finden.

    edit: Ich bin ja so blind 🕶

    C++-Standard schrieb:

    For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type
    yield a total order, even if the built-in operators <, >, <=, >= do not.



  • SeppJ schrieb:

    Ja, echt exotisch diese 286er mit ihrem MS-DOS 🙂 .

    Als die Dinger modern waren, war ich ja noch nicht mal geboren. 🤡

    SeppJ schrieb:

    blind 🕶

    Wer braucht schon mehr Smilies, wenn man die alten umfunktionieren kann.



  • SeppJ schrieb:

    cooky451 schrieb:

    Müssen ja lustige Maschinen sein, bei denen das nicht klappt.

    Ja, echt exotisch diese 286er mit ihrem MS-DOS 🙂 .

    Mal nachdenken... man bräuchte ein Speichermodell mit far-Daten, und ein Pointervergleich dürfte nur die Offsets vergleichen und stillschweigend voraussetzen, dass die Segmentanteile gleich sind. Ergibt Sinn.


Anmelden zum Antworten