 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Ernst Barner Guest
|
Posted: Sun Apr 25, 2004 7:00 pm Post subject: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Hallo allerseits,
zu Destruktoren / Konstruktoren habe ich ein paar einfache Fragen:
1)
Wenn kein Konstruktor vom Programmierer implementiert wird, dann wird
vom Compiler ein Standard-Konstruktor (d.h. ohne Parameter und ohne
Anweisungenen) erzeugt.
Angenommen, vom Programmierer wird kein Destruktor implementiert.
Wird dann vom Compiler automatisch auch (analog wie beim Konstruktor)
ein Destruktor erzeugt ?
2)
a) Der Destruktor ist dazu da, "Aufräumarbeiten" zu verrichten.
Bei der Benutzung von dynamischem Speicher wird im Konstruktor
Speicher angelegt und im Destruktor wieder freigegeben.
Im folgenden Demo-Programm unten wird dies demonstriert.
In dem Buch Visual C++ von Martin Aupperle wird empfohlen, auch bei
einfachen Datentypen wie char, int, usw. new und delete statt malloc
und free zu benutzen.
Ich habe das auch in dem Demo-Programm unten so gemacht.
Allerdings habe ich in einigen Büchern (auch in dem von Aupperle)
gesehen, daß immer noch in einigen Beispielen malloc und free benutzt
wird (anstatt new und delete).
a) Ist es richtig, immer statt malloc und free besser new und delete
zu verwenden.
b) Ist das folgende Demo-Programm korrekt ?
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
class MyString{
private:
char *text;
public:
MyString(char *str);
~MyString();
};
MyString::MyString(char *str){
int len;
len = strlen(str);
text = new char[len+1];
strcpy(text, str);
};
MyString::~MyString(){
delete[]text;
};
void main(){
MyString s("Hallo");
}
3)
Im Buch von Aupperle steht ausserdem:
"...delete dient zur Zerstörung eines dynamisch erzeugten Objekts...
delete ruft zunächst den Destruktor auf (falls vorhanden) und gibt
dann den allokierten Speicherbereich wieder frei"
Diese Logik verstehe ich nun nicht mehr:
Im Destruktor steht (wie oben bei ~MyString()) die Anweisung delete.
Diese ruft wieder den Destruktor auf. Gibt das nicht eine Rekursion ?
mfg
Ernst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Sun Apr 25, 2004 7:40 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner wrote:
| Quote: | Hallo allerseits,
zu Destruktoren / Konstruktoren habe ich ein paar einfache Fragen:
1)
Wenn kein Konstruktor vom Programmierer implementiert wird, dann wird
vom Compiler ein Standard-Konstruktor (d.h. ohne Parameter und ohne
Anweisungenen) erzeugt.
|
Ja.
| Quote: | Angenommen, vom Programmierer wird kein Destruktor implementiert.
Wird dann vom Compiler automatisch auch (analog wie beim Konstruktor)
ein Destruktor erzeugt ?
|
Ja.
| Quote: | 2)
a) Der Destruktor ist dazu da, "Aufräumarbeiten" zu verrichten.
Bei der Benutzung von dynamischem Speicher wird im Konstruktor
Speicher angelegt und im Destruktor wieder freigegeben.
|
Das ist ein mögliches Beispiel.
| Quote: | Im folgenden Demo-Programm unten wird dies demonstriert.
In dem Buch Visual C++ von Martin Aupperle wird empfohlen, auch bei
einfachen Datentypen wie char, int, usw. new und delete statt malloc
und free zu benutzen. Ich habe das auch in dem Demo-Programm unten so
gemacht.
Allerdings habe ich in einigen Büchern (auch in dem von Aupperle)
gesehen, daß immer noch in einigen Beispielen malloc und free benutzt
wird (anstatt new und delete).
a) Ist es richtig, immer statt malloc und free besser new und delete
zu verwenden.
|
Es gibt auch keinen Grund, malloc und free zu benutzen. new/delete ist
konsistenter, da man es für Klassen sowieso benutzen muß. malloc kann
nur mit PODs (also eingebauten Typen oder Klassen ohne Konstruktoren,
Destruktoren, Basisklassen, virtuelle Funktionen, private-Member u.s.w)
eingesetzt werden, und man darf einen mit malloc allokieren
Speicherbereich nicht mit delete freigeben. Genausowenig darf man new
und free mischen.
| Quote: | b) Ist das folgende Demo-Programm korrekt ?
#include "stdafx.h"
|
Das ist kein Standardheader.
| Quote: | #include "stdio.h"
#include "string.h"
|
Systemheader werden mit < und > included, nicht mit "".
| Quote: | class MyString{
private:
char *text;
public:
MyString(char *str);
|
Sollte besser sein:
MyString(const char *str);
Deine Klasse hält sich nicht an die "Rule of Three", die besagt, daß
man, wenn man einen Kopierkonsturktor, Zuweisungsoperator oder
Destruktor braucht, man höchstwahrscheinlich alle drei benötigt. Bei
deiner Klasse ist dies der Fall. Falls du da mehr drüber wissen willst,
kannst du ja nochmal nachfragen
Aber ich weiß nicht, auf welchem Wissensstand du so bist und ob du daher
schon was damit anfangen kannst. Erstmal mußt du wissen, wie der
Kopierkonsturktor und der Zuweisungoperator verwendet und implementiert
werden. Wenn du das noch nicht weißt, denk erstmal nicht weiter drüber
nach. Das mit der Rule of Three kommt dann später :)
| Quote: | MyString::MyString(char *str){
int len;
len = strlen(str);
text = new char[len+1];
strcpy(text, str);
};
MyString::~MyString(){
delete[]text;
};
|
Deine Verwendung von new[] und delete[] ist soweit korrekt.
main muß int zurückliefern.
| Quote: | MyString s("Hallo");
}
3)
Im Buch von Aupperle steht ausserdem:
"...delete dient zur Zerstörung eines dynamisch erzeugten Objekts...
delete ruft zunächst den Destruktor auf (falls vorhanden) und gibt
dann den allokierten Speicherbereich wieder frei"
Diese Logik verstehe ich nun nicht mehr:
Im Destruktor steht (wie oben bei ~MyString()) die Anweisung delete.
Diese ruft wieder den Destruktor auf. Gibt das nicht eine Rekursion ?
|
Nein. delete ruft den Destruktor des Objekts auf, daß du damit löschen
willst. Da es sich in diesem Fall um Objekte vom Typ char handelt,
gibt's aber keinen Destruktor, der dazu aufgerufen werden kann.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Horst Kraemer Guest
|
Posted: Mon Apr 26, 2004 9:31 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
On Sun, 25 Apr 2004 21:00:48 +0200, Ernst Barner <carlox (AT) web (DOT) de>
wrote:
| Quote: | class MyString{
private:
char *text;
public:
MyString(char *str);
~MyString();
};
|
| Quote: | MyString::MyString(char *str){
int len;
len = strlen(str);
text = new char[len+1];
strcpy(text, str);
};
|
MyString::~MyString(){
delete[]text;
};
| Quote: | 3)
Im Buch von Aupperle steht ausserdem:
"...delete dient zur Zerstörung eines dynamisch erzeugten Objekts...
delete ruft zunächst den Destruktor auf (falls vorhanden) und gibt
dann den allokierten Speicherbereich wieder frei"
|
| Quote: | Diese Logik verstehe ich nun nicht mehr:
Im Destruktor steht (wie oben bei ~MyString()) die Anweisung delete.
Diese ruft wieder den Destruktor auf. Gibt das nicht eine Rekursion ?
|
Wenn Du sagst:
MyString* s = new("Hallo");
delete s;
Ruft "delete s" zunaechst MyString::~MyString auf, bevor es den
Speicherplatz fuer s freigibt. Das delete [] text zerstoert nur
s->text, also das, auf das der Zeiger s-> text zeigt, und gibt dann
den Speicherplatz fuer s->text frei. Formal wird dazu Destruktor fuer
char-Arrays aufgerufen, aber in Praxis passiert da nichts, da man
chars einfach ohne "Nachsorge" wegwerfen kann.
Das Ganze ist also gestaffelt. MyString::~MyString besorgt nur die
Freigabe des Speichers fuer das Klassenelement s->text. Ohne diesen
Destruktor wuerde delete s nur den Speicher fuer s freigeben, und der
fuer s->text allokierte Speicherplatz waere verloren (memory leak).
--
Horst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Tibor Pausz Guest
|
Posted: Mon Apr 26, 2004 10:33 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner <carlox (AT) web (DOT) de> wrote:
| Quote: | b) Ist das folgende Demo-Programm korrekt ?
|
Nein, andere Punkt sind bereits angesprochen worden
#include <cstring>
// ist die ISO C++ Schreibweise für den Header
class MyString {
private:
char* text;
MyString& operator= (MyString const&);
// Hier wird ein eigener Assigment Operator deklariert
MyString (MyString const&);
// Hier wird ein eigener Kopierkonstruktor deklariert
// anderfalls hättest Du ein Resourcenleck, wenn Du Objekte
// durch Kopieren konstruiertst bzw. durch Zuweisung neue Werte
// zuweist.
// implementieren tun wir sie nicht
public:
MyString (char const* str);
~MyString ();
};
MyString::MyString (char const* str){
size_t const len = strlen (str);
// strlen liefert ein size_t zurück
// es gibt Plattformen auf denen size_t Werte den Wertebereich
// von int überschreiten, daher niemals ints size_t Werte zuweisen
// ohne vorher den Wertebereich überprüft zu haben
text = new char[len+1];
strcpy (text, str);
};
// bzw. die alternative Formulierung mit Initialisierung
MyString::MyString (char const* str) :
text (new char[strlen(str) + 1])
{
strcpy (text, str);
}
MyString::~MyString(){
delete[] text;
};
int main() {
MyString s("Hallo");
}
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Helmut Zeisel Guest
|
Posted: Mon Apr 26, 2004 1:01 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Tibor Pausz wrote:
| Quote: | #include
// ist die ISO C++ Schreibweise für den Header
|
Der Ordnung zuliebe: die Funktionen sind dann aber im namespace std;
| Quote: | MyString::MyString (char const* str){
size_t const len = strlen (str);
|
Das muss dann std::strlen sein (oder "using")
| Quote: | strcpy (text, str);
|
ebenso std::strcpy
Helmut
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Marco Budde Guest
|
Posted: Mon Apr 26, 2004 5:14 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner wrote:
| Quote: | Wenn kein Konstruktor vom Programmierer implementiert wird, dann wird
vom Compiler ein Standard-Konstruktor (d.h. ohne Parameter und ohne
Anweisungenen) erzeugt.
Angenommen, vom Programmierer wird kein Destruktor implementiert.
Wird dann vom Compiler automatisch auch (analog wie beim Konstruktor)
ein Destruktor erzeugt ?
|
Ja, aber dieser zerstört natürlich keine dynamisch angelegten
Objekte.
| Quote: | Bei der Benutzung von dynamischem Speicher
|
Dessen Verwendung man in C++ möglichst vermeidet.
| Quote: | wird im Konstruktor
Speicher angelegt und im Destruktor wieder freigegeben.
|
Kann man machen, ja.
| Quote: | In dem Buch Visual C++ von Martin Aupperle wird empfohlen,
|
Der Name (Compiler im Titel) läßt nichts gutes vermuten.
| Quote: | auch bei
einfachen Datentypen wie char, int, usw. new und delete statt malloc
und free zu benutzen.
|
malloc und free kannst Du komplett vergessen.
| Quote: | Allerdings habe ich in einigen Büchern (auch in dem von Aupperle)
gesehen, daß immer noch in einigen Beispielen malloc und free benutzt
wird (anstatt new und delete).
|
Wegwerfen.
| Quote: | a) Ist es richtig, immer statt malloc und free besser new und delete
zu verwenden.
|
Ja.
| Quote: | b) Ist das folgende Demo-Programm korrekt ?
#include "stdafx.h"
|
Proprietärer Müll von MS, weglassen.
| Quote: | #include "stdio.h"
#include "string.h"
|
Wenn Dein Buch das so zeigt, wegwerfen da veraltet und falsch.
Die Anführungszeichen benutzt man nur bei "lokalen" Headern.
Systemheader benutzen spitze Klammern.
Richtig wäre:
#include <cstdio>
#include <cstring> oder <string>
using namespace std;
| Quote: | class MyString{
private:
char *text;
public:
MyString(char *str);
|
Verändert der ctor den Parameter "str" intern? Nein, also konstant
machen:
MyString(const char *str);
Nebenbei verwendet man für Strings in C++ eher std::string.
Du meinst
int main()
{
| Quote: | Im Destruktor steht (wie oben bei ~MyString()) die Anweisung delete.
Diese ruft wieder den Destruktor auf. Gibt das nicht eine Rekursion ?
|
Nein, erst wird der dtor ausgeführt und dann wird der
Speicher der Instanz von "MyString" freigegeben.
cu, Marco
--
S: Minolta: Winkelsucher (VN), VC-9
E-Mail: mb-news-b<ät>linuxhaven.de
Deutsches Linux HOWTO Projekt: http://www.linuxhaven.de
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Ernst Barner Guest
|
Posted: Mon Apr 26, 2004 7:15 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Also angenommen man hat die zwei folgenden Programme (mit den oben
genannten Klassen, Methoden usw.), konkret:
// Programm 1
int main() {
MyString s("Hallo");
}
Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
Den Destruktoraufruf kann man sich in der schliessenden geschweiften
Klammer } bei main konzentriert denken (zumindest steht das so im Buch
von Aupperle).
Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und gibt
dann automatisch (ohne dass dies explizit durch eine Anweisung
geschieht) den vorher durch den Konstruktor reservierten Speicherplatz
s wieder frei.
Ist das korrekt ?
// Programm 2
int main() {
MyString s("Hallo");
delete s
}
Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
delete s ruft zuerst den Destruktor auf, der den allokierten Speicher
text wieder freigibt. Zusätzlich gibt delete s den Speicherplatz s
wieder frei.
Jetzt kommt aber die schliessende geschweifte Klammer } (in der man
sich den Destruktoraufruf konzentriert vorstellen kann) von main und
es geht weiter wie oben:
Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und dann
automatisch (ohne dass dies explizit durch eine Anweisung geschieht)
den vorher durch den Konstruktor reservierten Speicherplatz s wieder
frei.
Das heißt text und s wird insgesamt 2 mal freigegeben. Das kann doch
nicht sein. Was ist falsch ?
Was ist besser:
Program 1 oder Programm 2 ?
mfg Ernst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Ernst Barner Guest
|
Posted: Mon Apr 26, 2004 7:15 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
| Quote: |
class MyString {
private:
char* text;
MyString& operator= (MyString const&);
// Hier wird ein eigener Assigment Operator deklariert
MyString (MyString const&);
// Hier wird ein eigener Kopierkonstruktor deklariert
// anderfalls hättest Du ein Resourcenleck, wenn Du Objekte
// durch Kopieren konstruiertst bzw. durch Zuweisung neue Werte
// zuweist.
// implementieren tun wir sie nicht
Warum braucht man |
MyString& operator= (MyString const&) und
MyString (MyString const&)
nicht implementieren bzw. warum hast du sie nicht implementiert ?
| Quote: |
public:
MyString (char const* str);
~MyString ();
};
MyString::MyString (char const* str){
size_t const len = strlen (str);
// strlen liefert ein size_t zurück
// es gibt Plattformen auf denen size_t Werte den Wertebereich
// von int überschreiten, daher niemals ints size_t Werte zuweisen
// ohne vorher den Wertebereich überprüft zu haben
text = new char[len+1];
strcpy (text, str);
};
// bzw. die alternative Formulierung mit Initialisierung
warum ist diese Version mit _Initialisierung_ ?
MyString::MyString (char const* str) :
text (new char[strlen(str) + 1])
{
strcpy (text, str);
}
MyString::~MyString(){
delete[] text;
};
int main() {
MyString s("Hallo");
}
|
mfg
Ernst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Mon Apr 26, 2004 11:58 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner wrote:
| Quote: | class MyString {
private:
char* text;
MyString& operator= (MyString const&);
// Hier wird ein eigener Assigment Operator deklariert
MyString (MyString const&);
// Hier wird ein eigener Kopierkonstruktor deklariert
// anderfalls hättest Du ein Resourcenleck, wenn Du Objekte
// durch Kopieren konstruiertst bzw. durch Zuweisung neue Werte
// zuweist.
// implementieren tun wir sie nicht
Warum braucht man
MyString& operator= (MyString const&) und
MyString (MyString const&)
nicht implementieren bzw. warum hast du sie nicht implementiert ?
|
Das steht im Zusammenhang mit meinem Hinweis auf die Rule of Three. Du
bekommst ein großes Problem, wenn mal einer deiner Strings irgendwo
kopiert wird. Der Compiler erzeugt nämlich den Kopierkonsturktor und
den Zuweisungsoperator automatisch für dich, falls du es nicht tust.
Diese erzeugen memberweise eine Kopie des Objekts. Das wäre aber in
deinem Fall nicht das richtige, da dann ja nur der Zeiger kopiert wird.
Nachher hast du also zwei Objekte, die einen Zeiger auf den selben
Speicher haben. Beim Zersören einer Kopie würde der anderen der
Speicher unterm A**** weggeklaut werden. Es gibt nun zwei Lösungen. Die
einfach ist, Kopierkonstruktor und Zuweisungsoperator privat zu
deklarieren und nicht zu definieren. Dadurch kommt in jedem Fall eine
Fehlermeldung, falls man irgendwo versuchen sollte, eine Instanz deiner
Klasse zu kopieren. Das Objekt wird also einfach vor dem
Kopierversuchen geschützt. Die andere Variante ist natürlich, die
beiden so zu implementieren, daß sie das richtige tun.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Tue Apr 27, 2004 12:05 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner wrote:
| Quote: | Also angenommen man hat die zwei folgenden Programme (mit den oben
genannten Klassen, Methoden usw.), konkret:
// Programm 1
int main() {
MyString s("Hallo");
}
Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
|
Genau.
| Quote: | Den Destruktoraufruf kann man sich in der schliessenden geschweiften
Klammer } bei main konzentriert denken (zumindest steht das so im Buch
von Aupperle).
|
Das stimmt auch - sofern keine Exceptions ins Spiel kommen. In dem Fall
kommt die Funktion nicht bis zur geschweiften Klammer, aber der
Destruktor wird trotzdem aufgerufen.
| Quote: | Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und gibt
dann automatisch (ohne dass dies explizit durch eine Anweisung
geschieht) den vorher durch den Konstruktor reservierten Speicherplatz
s wieder frei.
Ist das korrekt ?
|
Das delete[]text; gibt nur den Speicher, auf den text zeigt wieder frei,
sonst nichts. Es hat mit dem Speicher, in dem MyString steht, nichts zu
tun. Dieser wird beim Verlassen der Funktion freigegeben.
| Quote: | // Programm 2
int main() {
MyString s("Hallo");
delete s
}
Was passiert im einzelnen ?
|
Der Compiler meldet einen Syntaxfehler oder zwei
Das müßte eher lauten:
int main() {
MyString* s = new MyString("Hallo");
delete s;
}
| Quote: | Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
delete s ruft zuerst den Destruktor auf, der den allokierten Speicher
text wieder freigibt. Zusätzlich gibt delete s den Speicherplatz s
wieder frei.
Jetzt kommt aber die schliessende geschweifte Klammer } (in der man
sich den Destruktoraufruf konzentriert vorstellen kann) von main und
es geht weiter wie oben:
Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und dann
automatisch (ohne dass dies explizit durch eine Anweisung geschieht)
den vorher durch den Konstruktor reservierten Speicherplatz s wieder
frei.
Das heißt text und s wird insgesamt 2 mal freigegeben. Das kann doch
nicht sein. Was ist falsch ?
|
Du kannst ein Objekt, das nicht mit new angelegt wurde, auch nicht mit
delete wieder freigeben.
| Quote: | Was ist besser:
Program 1 oder Programm 2 ?
|
Programm 1, weil es funktioniert.
PS: Du plenkst!
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Horst Kraemer Guest
|
Posted: Tue Apr 27, 2004 12:06 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
On Mon, 26 Apr 2004 21:15:34 +0200, Ernst Barner <carlox (AT) web (DOT) de>
wrote:
| Quote: | Also angenommen man hat die zwei folgenden Programme (mit den oben
genannten Klassen, Methoden usw.), konkret:
// Programm 1
int main() {
MyString s("Hallo");
}
Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
Den Destruktoraufruf kann man sich in der schliessenden geschweiften
Klammer } bei main konzentriert denken (zumindest steht das so im Buch
von Aupperle).
|
Korrekt.
| Quote: | Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und gibt
dann automatisch (ohne dass dies explizit durch eine Anweisung
geschieht) den vorher durch den Konstruktor reservierten Speicherplatz
s wieder frei.
Ist das korrekt ?
|
Nein. delete [] text tut das, was dransteht, es ist nur fuer die
fachgerechte Entsorgung dessen zustaendig, auf das der Zeiger 'text'
zeigt und es tut nichts anderes. Es macht ausschließlich das
rueckgaengig, was Du im c'tor per
text = new char[..];
angelegt hast. Die Freigabe des Speichers fuer s wird vom System im
Zuge der Rueckkehr der Funktion main besorgt.
| Quote: |
// Programm 2
int main() {
MyString s("Hallo");
delete s
}
|
Das geht nicht. delete darf nur auf Zeiger angewendet werden
Mein verkorkstes Beispiel, das ich Dir geben wollte, haette
int main()
{
MyString *p = new MyString("Hallo");
delete p;
}
lauten sollen. Ich hatte versehentlich
MyString *p = new ("Hallo");
geschrieben, was natuerlich Unsinn ist.
| Quote: | Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
delete s ruft zuerst den Destruktor auf, der den allokierten Speicher
text wieder freigibt. Zusätzlich gibt delete s den Speicherplatz s
wieder frei.
Jetzt kommt aber die schliessende geschweifte Klammer } (in der man
sich den Destruktoraufruf konzentriert vorstellen kann) von main und
es geht weiter wie oben:
Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und dann
automatisch (ohne dass dies explizit durch eine Anweisung geschieht)
den vorher durch den Konstruktor reservierten Speicherplatz s wieder
frei.
Das heißt text und s wird insgesamt 2 mal freigegeben. Das kann doch
nicht sein. Was ist falsch ?
Was ist besser:
Program 1 oder Programm 2 ?
mfg Ernst
|
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Horst Kraemer Guest
|
Posted: Tue Apr 27, 2004 12:18 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
On Mon, 26 Apr 2004 21:15:34 +0200, Ernst Barner <carlox (AT) web (DOT) de>
wrote:
| Quote: | Also angenommen man hat die zwei folgenden Programme (mit den oben
genannten Klassen, Methoden usw.), konkret:
// Programm 1
int main() {
MyString s("Hallo");
}
Was passiert im einzelnen ?
Durch MyString s("Hallo"); wird Speicherplatz bereitgestellt und der
Konstruktor aufgerufen.
Den Destruktoraufruf kann man sich in der schliessenden geschweiften
Klammer } bei main konzentriert denken (zumindest steht das so im Buch
von Aupperle).
|
Korrekt.
| Quote: | Die Anweisung
delete[]text;
im Destruktor gibt den allokierten Speicher text wieder frei und gibt
dann automatisch (ohne dass dies explizit durch eine Anweisung
geschieht) den vorher durch den Konstruktor reservierten Speicherplatz
s wieder frei.
Ist das korrekt ?
|
Nein. delete [] text tut das, was dransteht, es ist nur fuer die
fachgerechte Entsorgung dessen zustaendig, auf das der Zeiger 'text'
zeigt und es tut nichts anderes. Es macht ausschließlich das
rueckgaengig, was Du im c'tor per
text = new char[..];
angelegt hast. Die Freigabe des Speichers fuer s wird vom System im
Zuge der Rueckkehr der Funktion main besorgt.
| Quote: |
// Programm 2
int main() {
MyString s("Hallo");
delete s
}
|
Das geht nicht. delete darf nur auf Zeiger angewendet werden
Mein Beispiel, das ich Dir geben wollte, haette
int main()
{
MyString *p = new MyString("Hallo");
delete p;
}
lauten sollen. Ich hatte versehentlich
MyString *p = new ("Hallo");
geschrieben, was natuerlich Unsinn ist.
Hierbei passiert folgendes.
new beschafft Speicherplatz fuer ein dynamisches Objekt von Typ
MyString, laesst den c'tor ausfuehren und gibt einen Zeiger auf das
Objekt zurueck, der der Variablen p zugewiesen wird. Hier ist p also
kein Objekt vom Typ Mystring, sondern ein Zeiger, der auf ein Objekt
vom Typ MyString Zeigt. Der c'tor beschafft innerhalb des Objekts
Speicherplatz fuer den Zeiger text.
delete p ruft den d'tor ~MyString auf, innerhalb dessen delete [] text
den Speicherplatz fuer text freigibt. Danach gibt delete p den
Speicherplatz fuer das MyString-Objekt frei, auf das p zeigt. Jetzt
ist nur noch ein nackter Zeiger p uebriggeblieben, der auf nichts mehr
zeigt. Die schließende Klammer tut nichts mehr, ausser dass sie
sozusagen die tote Variable p wegwirft. Sie ruft auch keinen d'tor
mehr auf, da Destruktoren nur fuer Variablen eines Klassentyps
automatisch beim Verlassen einer Funktion aufgerufen werden, und p ist
keine Variable eines Klassentyps, sondern ein Zeigervariable, die auf
ein Objekt eines Klassentyps zeigt.
Haben sich die Fragen jetzt etwas gelichtet ?
--
Horst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Tibor Pausz Guest
|
Posted: Tue Apr 27, 2004 7:02 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner <carlox (AT) web (DOT) de> wrote:
| Quote: | Warum braucht man
MyString& operator= (MyString const&) und
MyString (MyString const&)
nicht implementieren bzw. warum hast du sie nicht implementiert ?
|
Ich wollte die Klasse korrekt implementieren, aber Dich erstmal nicht
mit einer kopierfähigen Implementation belasten, da Du so etwas in
Deinem Beispiel ebenfalls nicht versucht hast.
| Quote: | warum ist diese Version mit _Initialisierung_ ?
MyString::MyString (char const* str) :
text (new char[strlen(str) + 1])
{
strcpy (text, str);
}
|
Da Du Deine Klasse nicht kopierfähig designt hast, wäre die logische
Konsequenz sie etwas anders zu implementieren. Man könnte den Zeiger
dann gleich const definieren, da er während seiner Existenz nicht
geändert werden braucht und sollte. In anderen Member Functions kannst
Du ihn jetzt nicht mehr irrtümlic überschreiben. Aber const Zeiger kann
man nur initialisieren genauso wie Referenzen. Daher solltest Du Dich
daran gewöhnen, daß man üblicherweise Initialisierung der Zuweisung im
Konstruktor vorzieht.
class MyString {
size_t size_;
char *const text_;
MyString& operator= (MyString const&);
MyString (MyString const&);
public:
MyString (char const* text) :
size_ (std::strlen(text)), text_ (new char[size_ + 1])
{
std::strcpy (text_, text);
}
~MyString () {
delete[] text_;
}
};
Eine simple mögliche Implementation (Deep Copy) vom Kopierkonstruktor
und AssigmentOperator sähe so aus.
class MyString
...
char* text_;
// der Rest wie oben
...
};
MyString::MyString (MyString const& rhs) :
size_ (rhs.size_), text_ (new char [size_ + 1])
{
std::strcpy (text_, rhs.text_);
}
MyString&
MyString::operator= (MyString const& rhs) {
char* tmpText_ = new char[rhs.size_ + 1];
std::strcpy (tmpText_, rhs.text_);
delete[] this->text_;
this->size_ = rhs.size_;
this->text_ = tmpText_;
return *this_;
}
Alternativ kann man natürlich andere Idiome implementieren, etwa
ReferenzCounting.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Ernst Barner Guest
|
Posted: Tue Apr 27, 2004 6:32 pm Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
| Quote: |
Nein. delete [] text tut das, was dransteht, es ist nur fuer die
fachgerechte Entsorgung dessen zustaendig, auf das der Zeiger 'text'
zeigt und es tut nichts anderes. Es macht ausschließlich das
rueckgaengig, was Du im c'tor per
text = new char[..];
angelegt hast.
delete [] text ruft außerdem den "Konstruktor" von char auf (so wie du |
es geschrieben hast).
Da es diesen nicht gibt, wird auch nichts gemacht.
| Quote: |
Die Freigabe des Speichers fuer s wird vom System im
Zuge der Rueckkehr der Funktion main besorgt.
Dann ist der folgende Satz im Buch von Aupperle wohl falsch: |
"Ein Destruktor ist in gewisser Weise das Gegenteil eines
Konstruktors, weil der vorher im Konstruktor zugewiesene Speicherplatz
im Destruktor wieder freigegeben wird."
Der Speicherplatz wird nicht vom Destruktor, sondern vom System
freigegeben.
| Quote: |
Hierbei passiert folgendes.
new beschafft Speicherplatz fuer ein dynamisches Objekt von Typ
MyString, laesst den c'tor ausfuehren und gibt einen Zeiger auf das
Objekt zurueck, der der Variablen p zugewiesen wird. Hier ist p also
kein Objekt vom Typ Mystring, sondern ein Zeiger, der auf ein Objekt
vom Typ MyString Zeigt. Der c'tor beschafft innerhalb des Objekts
Speicherplatz fuer den Zeiger text.
delete p ruft den d'tor ~MyString auf, innerhalb dessen delete [] text
den Speicherplatz fuer text freigibt. Danach gibt delete p den
Speicherplatz fuer das MyString-Objekt frei, auf das p zeigt. Jetzt
ist nur noch ein nackter Zeiger p uebriggeblieben, der auf nichts mehr
zeigt. Die schließende Klammer tut nichts mehr, ausser dass sie
sozusagen die tote Variable p wegwirft. Sie ruft auch keinen d'tor
mehr auf, da Destruktoren nur fuer Variablen eines Klassentyps
automatisch beim Verlassen einer Funktion aufgerufen werden, und p ist
keine Variable eines Klassentyps, sondern ein Zeigervariable, die auf
ein Objekt eines Klassentyps zeigt.
Das folgende habe ich nicht gewußt: |
Ein Destruktor wird nicht für Zeigervariablen auf Klassentyps beim
Verlassen einer Funktion aufgerufen.
| Quote: |
Haben sich die Fragen jetzt etwas gelichtet ?
Ich hoffe ja und bedanke mich deshalb erst einmal bei allen |
Mitdiskutierenden.
mfg
Ernst
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Wed Apr 28, 2004 8:55 am Post subject: Re: Einfache Frage zu KONSTRUKOR / DESTRUKTOR |
|
|
Ernst Barner wrote:
| Quote: | Nein. delete [] text tut das, was dransteht, es ist nur fuer die
fachgerechte Entsorgung dessen zustaendig, auf das der Zeiger 'text'
zeigt und es tut nichts anderes. Es macht ausschließlich das
rueckgaengig, was Du im c'tor per
text = new char[..];
angelegt hast.
delete [] text ruft außerdem den "Konstruktor" von char auf (so wie du
es geschrieben hast).
Da es diesen nicht gibt, wird auch nichts gemacht.
|
Warum sollte delete den Konstruktor aufrufen? Das wird in new gemacht.
Oder meintest du den Destruktor?
| Quote: | Die Freigabe des Speichers fuer s wird vom System im
Zuge der Rueckkehr der Funktion main besorgt.
Dann ist der folgende Satz im Buch von Aupperle wohl falsch:
"Ein Destruktor ist in gewisser Weise das Gegenteil eines
Konstruktors, weil der vorher im Konstruktor zugewiesene Speicherplatz
im Destruktor wieder freigegeben wird."
Der Speicherplatz wird nicht vom Destruktor, sondern vom System
freigegeben.
|
Nein. Der Speicherplatz, den du im Konstruktor allokiert hast, wird
nicht vom System freigegeben. Das wird in deinem Destruktor erledigt.
Den Speicher für die Instanz deiner Klasse selbst hast du ja nicht in
ihrem Konstruktor belegt. Daher gibst du ihn auch im Destruktor nicht
wieder frei. Damit ist der Satz schon so einigermaßen korrekt. Deine
Klasse muß die Ressourcen -- es gibt ja nicht nur Speicher -- die sie
im Konstruktor belegt, im Destruktor wieder freigeben. Dein Objekt hat
mit der Beschaffung des Speichers, in dem es selbst steht, erstmal
nichts am Hut.
| Quote: | Das folgende habe ich nicht gewußt:
Ein Destruktor wird nicht für Zeigervariablen auf Klassentyps beim
Verlassen einer Funktion aufgerufen.
|
Etwas genauer formuliert: Die Zerstörung eines Zeigers ruft nicht den
Destruktor des Objekts auf, auf den er zeigt.
Wäre dem so, dann wären Zeiger recht nutzlos, da sie zusammen mit new
die Möglichkeit bieten, Objekte zu erzeugen, die über Funktionsgrenzen
hinweg existieren.
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|