Frage zu Objekten, Referenzen und Vererbung


  • Mod

    und STRPTR ist ein pointer auf char?



  • Soweit ich weiss, ja.


  • Mod

    dann liegt hier jede menge undefiniertes verhalten vor.

    MenuEntryC::MenuEntryC(const int type, const string label)
    {
        cout << "Create MenuEntry: " << this << " Label: " << label.c_str() << endl;
    
        strcpy(newMenu.nm_Label, label.c_str());
        newMenu.nm_Type = type;
        newMenu.nm_CommKey = 0;
        newMenu.nm_Flags = 0;
        newMenu.nm_MutualExclude = 0;
        newMenu.nm_UserData = NULL;
    }
    

    hier wird nm_label nicht initialisiert - das strcpy schreibt also irgendwo hin.



  • In allen C-Programmbeispielen, die systemkonform programmiert wurden, werden die Arrays aus struct NewMenu wie folgt angelegt:

    struct NewMenu gb_MenuDescribe[] =
    {
      { NM_TITLE, "Project",   NULL, 0, 0, NULL },
      { NM_ITEM,  "Quit",      NULL, 0, 0, NULL },
      { NM_END, NULL, NULL, 0, 0, NULL }
    };
    

    Ich versuche hier eine etwas dynamischere Variante. Im Bsp. hier werden die STRPTR doch auch nirgends initialisiert? Oder wird hierbei der STRPTR auf den Anfang der jeweils übergebenen Zeichenkette gelegt? Dann hab ich aber wieder das Problem aus meinem anderen Post, dass ich eine Struktur nicht in der Initialisierungsliste des CTors initialisieren kann!


  • Mod

    Reth schrieb:

    In allen C-Programmbeispielen, die systemkonform programmiert wurden, werden die Arrays aus struct NewMenu wie folgt angelegt:

    struct NewMenu gb_MenuDescribe[] =
    {
      { NM_TITLE, "Project",   NULL, 0, 0, NULL },
      { NM_ITEM,  "Quit",      NULL, 0, 0, NULL },
      { NM_END, NULL, NULL, 0, 0, NULL }
    };
    

    Ich versuche hier eine etwas dynamischere Variante. Im Bsp. hier werden die STRPTR doch auch nirgends initialisiert?

    Oder wird hierbei der STRPTR auf den Anfang der jeweils übergebenen Zeichenkette gelegt?

    korrekt. der typ eines stringliterals ist ein zeiger auf ein konstansten char, der auf die zeichenkette zeigt.

    Dann hab ich aber wieder das Problem aus meinem anderen Post, dass ich eine Struktur nicht in der Initialisierungsliste des CTors initialisieren kann!

    das musst du ja hier auch nicht tun. und du tust es ja bereits auch für die anderen member von NewMenu nicht. an nm_Label ist nichts besonderes, das dich hindert, ihm auf die selbe weise einen wert zuzuweisen.



  • Hi, danke hast recht.

    Ist mir gestern auch noch eingefallen, sollte dann ca. so funktionieren:

    newMenu.nm_Label = &(label.c_str()[0]);
    

    Wenn ich die Definition von c_str() noch korrekt im Kopf hab.



  • Dir ist schon klar, daß das von label.c_str() zurückgegebene char-Array höchstens so lange existiert wie das label-Objekt, ja? Spätestens wenn du newMenu nach der Destruktion von label verwendest, hast du ein Problem (wohlmöglich sogar deutlich früher).



  • Ja, da ich das Label aber mit:

    MenuC file("File", TRUE);
    

    im Hauptprogramm anlege, sollte es doch so lange existieren, bis file out of scope geht, oder nicht?

    Evtl. wäre es hier noch besser, wenn ich den Labelstring per Referenz übergebe, statt per Copy.

    Ciao



  • Der Text existiert solange bis das temporäre Objekt string( "File" ) out of scope geht. Das ist aber nach dem Semikolon in dieser Zeile. Ab diesem Zeitpunkt ist in einer Struktur tief in der API ein ungültiger Zeiger abgelegt.



  • Hm, das kapier ich jetzt nicht ganz, da das Objekt, welches mit:

    MenuC file("File", TRUE);
    

    angelegt wird doch so lange existiert, bis der umgebende Scope (Methode etc.) verlassen wird? Dachte ich zumindest? Oder nicht?



  • Das Objekt file ja, der String, der aus dem Literal "File" erzeugt wird, nicht.

    Was erwartet der File-Konstruktor? Ein std::string.
    Was gibst Du ihm? Ein const char*.

    Was passiert? Der Compiler entdeckt eine implizite Umwandlung von const char* nach string, bei der der Text kopiert wird. Der Konstruktor von MenuEntryC bekommt einen konstanten std::string, aus dem Du c_str() benutzt. Danach ist der Konstruktor beendet, der konstante std::string, der gebraucht wurde um const char* an MenuEntryC zu übergeben wird gelöscht, und Du stehst da mit einem Pointer, der aus einem c_str() eines jetzt nicht mehr gültigen Objektes stammt.



  • Wie kann ich dann in diesem Fall den String richtig initialisieren, damit er dauerhaft erhalten bleibt, bis file out of scope geht?



  • Übergib doch einfach direkt ein "const char*":

    MenuEntryC::MenuEntryC(const int type, const char* pLabel) 
    { 
        cout << "Create MenuEntry: " << this << " Label: " << pLabel << endl; 
    
        newMenu.nm_Label = pLabel;
        newMenu.nm_Type = type; 
        newMenu.nm_CommKey = 0; 
        newMenu.nm_Flags = 0; 
        newMenu.nm_MutualExclude = 0; 
        newMenu.nm_UserData = NULL; 
    }
    

    Edit: bei den abgeleiteten Klassen (z.B. MenuC) dann natürlich auch...



  • Das geht natürlich auch, wollte aber möglichst mit C++/STL-Konstrukten arbeiten,
    wobei der const char* hier bestimmt performanter ist, mich aber immer an C erinnert.

    Aber ich muss mich wohl damit abfinden, dass die Gemeinsamkeiten zw. C und C++ wohl größer sind als mir lieb wäre. Ich wäre in C++ auch gern ohne Zeiger ausgekommen, aber dann mutieren die STL-Container ja zu Speichermonstern, da immer kopiert wird.

    Ciao



  • Nur der Vollständigkeit halber:

    const char * hat nicht funktioniert, da STRPTR ein char * ist.
    Nachdem ich die Parameter in char * geändert habe, hats bestens funktioniert.



  • Trotzdem würde ich die Parameter als "const char *" übergeben und nur an der entsprechenden Zuweisung einen cast vornehmen:

    newMenu.nm_Label = const_cast<char *>(pLabel); // bzw <STRPTR>
    


  • Danke, werde ich probieren!

    Da fehlt mir halt die Erfahrung mit C++. Dachte der const_cast geht nur in die andere Richtung (also wenn ich was konstant machen will, was bisher noch nicht als konstant deklariert war).


Anmelden zum Antworten