Loeschen von Arrays im Destruktor



  • Angenommen ich habe folgende Klasse:

    class Test
    {
       private: 
         char *array = "12345";   
         //....diverse andere attribute
    
       public:
           //..diverse andere Methoden, setter/getter, Konstruktoren,...
    
          ~Test()
           {
               array=0;
    
           }
    };
    

    Reicht das array=0 oder muss ich erst noch jeden Eintrag auf 0 setzen und dann am Ende array=0 oder macht das alles der Kompiler automatisch beim Destruktoraufruf?



  • Hallo,

    Hier

    char *array = "12345";
    

    hast du der Variable array ein Stringliteral zugewiesen. Das brauchst du nicht löschen. array sollte hier auch const sein.



  • Genau genommen ist der Aufruf "array=0;" sogar überflüssig, da die Variable 'array' am Ende des Destruktors sowieso im Nirvana verschwindet. Solange du nur auf externe Daten verweist (wie in deinem Fall ein konstanter C-String), brauchst du dich im Destruktor nicht darum zu kümmern. Nur wenn du das Array selber angelegt hast (z.B. mit "array=new char[...];"), mußt du es wieder entsorgen (dazu brauchst du "delete[] array;").



  • Braunstein schrieb:

    Hallo,

    Hier

    char *array = "12345";
    

    hast du der Variable array ein Stringliteral zugewiesen. Das brauchst du nicht löschen.

    Warum nicht?

    Braunstein schrieb:

    array sollte hier auch const sein.

    Warum? Das kommt darauf an was ich damit machen will und ist aus diesem Beispiel nicht ersichtlich. Will ich das Array auch mal ändern macht const keinen Sinn.



  • CStoll schrieb:

    Genau genommen ist der Aufruf "array=0;" sogar überflüssig, da die Variable 'array' am Ende des Destruktors sowieso im Nirvana verschwindet. Solange du nur auf externe Daten verweist (wie in deinem Fall ein konstanter C-String), brauchst du dich im Destruktor nicht darum zu kümmern. Nur wenn du das Array selber angelegt hast (z.B. mit "array=new char[...];"), mußt du es wieder entsorgen (dazu brauchst du "delete[] array;").

    Ja das ist klar.

    Geht eigentlich auch sowas:
    array=new *char ...;

    und dann löschen mit delete[] array; ?

    *char ist ja auch ein Array oder schaut der Compiler nach dem new[] mit den Klammern und meckert dann wenn ich delete[] verwende, weil ich eben new *char benutzt habe und nicht new char[]?



  • Gast-1 schrieb:

    Angenommen ich habe folgende Klasse:

    class Test
    {
       private: 
         char *array = "12345";   
         //....diverse andere attribute
    
       public:
           //..diverse andere Methoden, setter/getter, Konstruktoren,...
    
          ~Test()
           {
               array=0;
               
           }
    };
    

    Reicht das array=0 oder muss ich erst noch jeden Eintrag auf 0 setzen und dann am Ende array=0 oder macht das alles der Kompiler automatisch beim Destruktoraufruf?

    Hi,

    das kommt ganz darauf an, was Du bewirken möchtest.
    Ich denke mal, in Deinem Fall ist das komplett unnötig/sinnlos/verwirrend.
    Mal ganz grundlegend:

    • Mit
    "12345"
    

    legst Du schon zur Compilezeit Speicher an. Den kannst Du nicht mehr zur Laufzeit ändern, Löschen, .... => "delete" o-ä. kommt nicht infrage

    • Mit
    char* array = "12345";
    

    drückst Du aus, dass Du einen Zeiger namens array auf diesen Speicherbereich zeigen lassen willst UND sowohl den Zeiger auf etwas anderes zeigen lassen , als auch den Wert, auf den er zeigt, ändern können willst.

    • Letzteres widerspricht schonmal Punkt 1, weswegen Du mindestens schreiben solltest:
    char const *array = "12345";
    

    (alternativ "const char*" - ist dasselbe) Eigentlich sollte der Compiler das auch anmeckern (min. als Warnung)
    Diese Deklaration hätte Deine Frage mit einfachem Ausprobieren beantwortet: "delete" darfst Du auf keinen solchen Pointer anwenden. 😉

    • Soll "array" auch niemals auf etwas anderes zeigen als auf diesen Speicherbereich, dann sollte der Zeiger selbst auch als "const" deklariert werden:
    char const * const array = "12345";
    

    Auf jeden Fall: Solchen Speicher kannst/darfst Du nicht "löschen".
    Du kannst natürlich im Destruktor array auf 0 setzen (wenn Du ihn nur "char const * array" deklariert hast) ... aber wozu ? Nach Abarbeten des Destruktors hört das Objekt sowieso auf, zu existieren, weswegen der "letzte Wert arrays vor dem Ableben" nicht mehr interessiert. 😃

    EDIT sagt, dass ich einfach zu langsam schreibe !! 😞 🙄

    Gruß,

    Simon2.



  • "12345" ist ein Stringliteral un wird vom Compiler als const char* aufgefasst. Du darfst darin nichts ändern. Dieses Literal wird vom Compiler an einer festen Stell im Speicher abgelegt und beim Beenden des Programmes aufgeräumt, also ist kein Löschen notwendig. Wenn du mit deinem String etwas machen willst solltest du den String dynamisch erstellen und mit strcpy zuweisen oder besser gleich mit std::string arbeiten.
    [edit]etwas spät 🙂 [edit]



  • Gast-1 schrieb:

    Warum? Das kommt darauf an was ich damit machen will und ist aus diesem Beispiel nicht ersichtlich. Will ich das Array auch mal ändern macht const keinen Sinn.

    String-Literale sind const (daß du mit einem nicht-konstanten Zeiger darauf verweisen darfst, hat etwas mit Abwärtskompatibilität zu tun), da löst du nur eine Schutzverletzung aus, wenn du dieses Array ändern willst.

    Wenn du etwas wirklich änderbares haben willst, mußt du selber den Speicher bereitstellen:

    class Test
    {
      char array[10];
    public:
      Test()
      {
        strcpy(array,"12345");
      }
    };
    
    //oder
    
    class Test
    {
      char*array;
    public:
      Test() : array(new char[10])
      {
        strcpy(array,"12345");
      }
      ~Test()
      {
         delete[]array;
      }
    };
    

    (die letzte Variante braucht noch Copy-Construktor und op=)

    Oder du verwendest gleich C++ Bordmittel - std::string oder std::vector<>.

    Gast-1 schrieb:

    *char ist ja auch ein Array oder schaut der Compiler nach dem new[] mit den Klammern und meckert dann wenn ich delete[] verwende, weil ich eben new *char benutzt habe und nicht new char[]?

    In dem Zusammenhang ist '*char' kein Array, sondern ein Zeiger - da würde der Compiler schon meckern, wenn du dessen Adresse im falschen Datentyp unterbringen willst.



  • Also gut dann sieht meine Klasse so aus: Die Klasse soll einen Text
    in einem char-Array aufnehmen und les und schreibbar sein:

    class Test
    {
       private: 
         char *array;
    
       public:
           Test(char *c)
           {
                array=c;
           }
    
           *char getText()  const
           {  return array; }
    
           void setText(const char *c) const
           {  array = c };
    
          ~Test()
           {
               //Was steht hier?
    
           }
    };
    

    Mit "12345" legst Du schon zur Compilezeit Speicher an. Den kannst Du nicht mehr zur Laufzeit ändern, Löschen, ....

    Achso, wusste ich nicht dass der nicht mehr änderbar ist.

    Mit char* array = "12345";
    drückst Du aus, dass Du einen Zeiger namens array auf diesen Speicherbereich zeigen lassen willst UND sowohl den Zeiger auf etwas anderes zeigen lassen , als auch den Wert, auf den er zeigt, ändern können willst.

    Ich dachte char *array = "12345";
    ist das selbe wie char[] = "12345";



  • Also deine Klasse kann so nicht funktionieren - in der Methode setText() sind die const's zu viel.

    (btw, char*a und char a[] sind nicht identisch - ersterer deklariert einen Zeiger auf (normalerweise) fremde Speicherbereiche, letzterer legt selber einen entsprechend großen Speicherblock an)



  • Hi!

    *char getText()  const
    

    Da is ein Syntaxfehler, der Stern is falsch gesetzt.

    ~Test()
    {
          //Was steht hier?         
    }
    

    Garnix steht da...

    grüße



  • CStoll schrieb:

    //oder
    class Test
    {
      char*array;
    
    public:
      Test() : array(new char[10])
      {
        strcpy(array,"12345");
      }
      ~Test()
      {
         delete[]array;
      }
    };
    

    (die letzte Variante braucht noch Copy-Construktor und op=)

    Genau sowas meinte ich, danke.
    Das mit den Zeigern und Arrays (genauer char arrays) bereitet mir immer noch Probleme.

    Oder du verwendest gleich C++ Bordmittel - std::string oder std::vector<>.

    Ja, klar aber das mit den Arrays und den Zeigern darauf und im Zusammenahng mit Klassen sollte man trotzdem kapieren, deshalb meine Frage hier ins Forum.

    Ich muss mal wieder die entsprechenden Kapitel in meinen Büchern durcharbeiten, ist lange her, als ich mit C++ zu tun hatte und das damals auch nur sporadisch, wie man unschwer an meinen dilettantischen Fragen erkennen konnte 😉

    Danke an euch.



  • CStoll schrieb:

    Also deine Klasse kann so nicht funktionieren - in der Methode setText() sind die const's zu viel.

    Stimmt, sonst wäre es nicht änderbar.

    Und der der Stern in getText() ist auch falsch, war ein Vertipper.

    (btw, char*a und char a[] sind nicht identisch - ersterer deklariert einen Zeiger auf (normalerweise) fremde Speicherbereiche, letzterer legt selber einen entsprechend großen Speicherblock an)

    Ja, das muss ich nochmal in Ruhe nachlesen, das muss man sicher beherrschen, sonst wird das nix mit einem funktionierenden Programm.



  • Gast-1 schrieb:

    ...
    Das mit den ... char arrays ...bereitet mir immer noch Probleme.
    ...

    Da das allen so geht, wurden ja Hilfsmittel wie string und die STL-Container geschrieben. 😉
    Aber es ist natürlich löblich, sich um korrektes Ressourcenhandling zu kümmern. Leider gibt's da keinen "Globalfall", sondern man muß für sich bei der Modellierung jedesmal wieder neu Gedanken darüber machen, wem jetzt eigentlich was gehört (und der ist dann für das Erzeugen und Löschen verantwortlich - im Idealfall).

    BTW:

    CStoll schrieb:

    ...
    (btw, char*a und char a[] sind nicht identisch - ersterer deklariert einen Zeiger auf (normalerweise) fremde Speicherbereiche, letzterer legt selber einen entsprechend großen Speicherblock an)

    Ich denke, er meinte eine Deklaration wie:

    char const *a1 = "12345";
        char const a2[] = "67890";
    

    In dem Zusammenhang ist das schon (im Wesentlichen) "dasselbe" (zumindestens kann man a1 und a2 identisch verwenden).

    Gruß,

    Simon2.



  • Simon2 schrieb:

    In dem Zusammenhang ist das schon (im Wesentlichen) "dasselbe" (zumindestens kann man a1 und a2 identisch verwenden).

    cout << sizeof(a1) << endl;
    cout << sizeof(a2) << endl;
    

    Nope. 😉



  • LordJaxom schrieb:

    Simon2 schrieb:

    In dem Zusammenhang ist das schon (im Wesentlichen) "dasselbe" (zumindestens kann man a1 und a2 identisch verwenden).

    cout << sizeof(a1) << endl;
    cout << sizeof(a2) << endl;
    

    Interessant was man hier alles erfährt ich glaube ich sollte mir mal ein neues Buch kaufen. Was empfehlt ihr denn als zeitgemässes Werk das auch solche C-Stolperfallen enthält oder sollte man sich dafür ein separates C-Buch kaufen? Dieses Zeigergewurschtel hat ja eigentlich nichts mit C++ zu tun.



  • LordJaxom schrieb:

    Simon2 schrieb:

    In dem Zusammenhang ist das schon (im Wesentlichen) "dasselbe" (zumindestens kann man a1 und a2 identisch verwenden).

    cout << sizeof(a1) << endl;
    cout << sizeof(a2) << endl;
    

    Nope. 😉

    Mir ist das schon klar, dass es nicht dasselbe ist....
    Deshalb mein "im Wesentlichen" und die Anführungszeichen um "dasselbe" .... damit meinte ich die Dinge, die unser Gast damit machen möchte: Zugreifen auf die Dateninhalte, Index-Verwendung, Pointerarithmetik, Allokationsverantwortung (ja, ich weiß, dass der Compiler dabei zwischen [] und * unterscheidet), ....
    und wenn ich recht informiert bin, legt

    char const array[] = "12345";
    

    nicht mehr den Speicher an als

    char const *array = "12345";
    

    ... was aber CStolls Grundbehauptung war. 😉

    Gast-1 schrieb:

    ...sollte man sich dafür ein separates C-Buch kaufen? Dieses Zeigergewurschtel hat ja eigentlich nichts mit C++ zu tun.

    Ich würde trotzdem ein C++-Buch vorziehen, weil da doch ein paar "Kleinigkeiten" anders laufen.
    Leider kann ich Dir dazu kein spezielles Werk empfehlen, weil ich mir selbst so'n Zeug aus unterschiedlichen Quellen zusammenklaube (aber für mich ist "Die C++-Programmiersprache" von Stroustrup - aktuellste Ausgabe - ein wichtiger Ausgangspunkt).

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Mir ist das schon klar, dass es nicht dasselbe ist....
    Deshalb mein "im Wesentlichen" und die Anführungszeichen um "dasselbe" ....

    <spitzfindig> In der Klammer schreibst Du aber ohne Einschränkung und Anführungszeichen "identisch" </spitzfindig>

    und wenn ich recht informiert bin, legt

    char const array[] = "12345";
    

    nicht mehr den Speicher an als

    char const *array = "12345";
    

    ... was aber CStolls Grundbehauptung war. 😉

    Wie ist der Satz zu verstehen? Wenn Du meinst, dass er in beiden Fällen keinen Heap-Speicher allokiert, hast Du recht. Im Sinne von "Speicher anlegen" wird aber die erste Variante (wenn in einer Funktion) auf dem Stack angelegt, bei der zweiten liegt der Text in irgendeinem (potentiell read-only) Datenbereich.



  • LordJaxom schrieb:

    ...

    <spitzfindig> In der Klammer schreibst Du aber ohne Einschränkung und Anführungszeichen "identisch" </spitzfindig>

    Hi,

    Wenn schon spitzfindig, dann richtig: Da

    cout << a1;
        cout << a2;
    

    beide verwendbar sind, kann ich sie "identisch verwenden" (vielleicht nicht in jedem Zusammenhang, aber das habe ich ja auch nicht behauptet). :p 😉
    Aber lass uns das mal beiseite legen.

    LordJaxom schrieb:

    ...
    ...wird aber die erste Variante (wenn in einer Funktion) auf dem Stack angelegt, ...

    EDIT: Hab's schon gefunden:
    http://c-faq.com/aryptr/
    bzw. direkt:
    http://c-faq.com/aryptr/aryptr2.html

    Gruß,

    Simon2.



  • char const array[] = "1234";
    

    Dies legt implizit ein Array der Größe 5 an und kopiert den String (+abschl. Null-Zeichen) in das Array.


Anmelden zum Antworten