Gültigkeitsbereich im Konstruktor
-
Hi,
wie kann ich das ändern? Etwa so?
class test { private: int *_var; public: test::test() { _var = new int; } };MfG
Scarabol
-
class test { private: int var1; public: test() : var1(0) { } };
-
Hi,
ich muss mein Problem präziser beschreiben:
Mein Problem ist das ich nicht alle Member der Klasse als class test speichern kann. Bei einigen kann ich nur class *test speichern. Wobei einige Werte für *test erst im Konstruktor erzeugt werden und dann bis zum Destruktor ihre Gültigkeit behalten sollen. Wie mach ich das richtig?MfG
Scarabol
-
Scarabol schrieb:
...
Mein Problem ist das ich nicht alle Member der Klasse als class test speichern kann. ...Hier wäre es gut, wenn Du kurz auf die Gründe eingehen könntest.
Natürlich ist "manuelle Objekterzeugung" bisweilen vonnöten - aber auch nicht immer. Der Umstand, dass die Initialwerte erst zur Laufzeit feststehen ist z.B. kein Grund (-> Initialisierungsliste) ... falls der Typ erst zur Laufzeit feststeht schon eher.
Wenn Du es tatsächlich brauchst, ist aber new der richtige Weg. Dann musst Du aber Einiges bedenken (z.B. verschiedene Situationen, in denen das Objekt kopiert wird) und entsprechend implementieren. smart-Pointer können Dir da weiterhelfen...
Deshalb würde ich immer solange wie irgend möglich versuchen, darauf zu verzichten.Gruß,
Simon2.
-
Scarabol schrieb:
ich muss mein Problem präziser beschreiben:
Also ich verstehe nach dieser "präzisen" Beschreibung nur noch Bahnhof (Da sind einige automatisch übersetzte Texte verständlicher).
Grundsätzlich gilt aber: Variablen die nicht nur innerhalb einer Methode, sondern über die Lebenszeit eines Objektes benötigt werden, sollten Membervariablen sein, oder jedesmal per Parameterübergabe mitgeliefert werden.
-
Sorry Leute,
hier mal mein Code:
class IGUIElement { public: IGUIElement(parent *p); ~IGUIElement(); private: long var1; long var2; }; class test { public: test(); ~test(); private: IGUIElement *_mainframe; };test::test() { _mainframe = new IGUIElement(this); }Also wenn ich nicht * vor mainframe verwende meckert der Compiler über einen fehlenden Konstruktor.
Wie mach ich das, dass _mainframe bis ~test() gültig bleibt?MfG
Scarabol
-
Bin mir nicht sicher ob ich das Problem verstehe, aber ich glaube die Lösung heißt Initialisierungsliste.
class test { public: test(); ~test(); private: IGUIElement _mainframe; };test::test() : _mainframe(this) { }
-
class test { public: test(); ~test(); private: IGUIElement _mainframe; }; // ... test::test() : _mainframe(this) { }Wobei ich jetzt mir aber grade nicht sicher bin, ob man this schon in der Initialisierungsliste verwenden darf (das Objekt ist ja noch gar nicht vollständig initialisiert). Ansonsten funktioniert die Variante von dir, per new angeforderter Speicher bleibt, bis er per delete freigegeben wird, und wenn das erst in ~test geschieht, lebt das Objekt eben auch so lange.
EDIT: zu spät...
-
Also kann ich eigentlich nichts verkehr machen wenn ich new und delete verwende?
Wenn ich bei ~test() vergesse delete aufzurufen, hab ich ein Speicherleck oder?
wenn ich delete IGUIELement aufrufe wird dann auch der Destruktor von IGUIElement aufgerufen?
MfG
Scarabol
-
Nein, ja, ja.
Verkehrt machen kannst du folgendes:
class test { public: test() { _mainframe = new IGUIElement(...); } ~test() { delete _mainframe; } private: IGUIElement *_mainframe; }; // ... int main() { test a, b; a = b; }Und schon hast du einen Crash. Warum? Weil bei der Zuweisung a = b der Zeiger _mainframe einfach stumpf kopiert wird. Am Ende der Funktion werden a und b zerstört, beide Destruktoren werden aufgerufen und auf den gleichen Zeiger wird 2 mal delete ausgeführt -> das geht schief. Um das zu verhindern musst du auch noch einen Zuweisungsoperator und einen Kopierkonstruktor definieren, die eine tiefe Kopie erzeugen. Google dazu auch mal nach der Regel der Großen Drei.
-
Cool danke an alle für die Hilfe jetzt weiß ich was ich wissen wollte.
MfG
Scarabol
-
ipsec schrieb:
Wobei ich jetzt mir aber grade nicht sicher bin, ob man this schon in der Initialisierungsliste verwenden darf (das Objekt ist ja noch gar nicht vollständig initialisiert).
Verwenden darf man es, man sollte nur Funktionsaufrufe etc. unterlassen, die auf diesen Speicher zugreifen (Der Zeiger an sich ist gültig, der Bereich dahinter aber noch nicht vollständig initialisiert).
-
Nur noch 2 kleine Ergänzungen, um das Bild abzurunden.
ipsec schrieb:
Nein, ja, ja.
Verkehrt machen kannst du folgendes:
class test { public: test() { _mainframe = new IGUIElement(...); } ~test() { delete _mainframe; } private: IGUIElement *_mainframe; }; // ... int main() { test a, b; a = b; }....auf den gleichen Zeiger wird 2 mal delete ausgeführt -> das geht schief. ...
+ er hat ein Speicherleck (das erste a::_mainframe wird nicht abgeräumt).
ipsec schrieb:
...Um das zu verhindern musst du auch noch einen Zuweisungsoperator und einen Kopierkonstruktor definieren, die eine tiefe Kopie erzeugen. ...
...oder die eine Kopie verhindern.
Gruß,
Simon2.
-
Scarabol schrieb:
Also kann ich eigentlich nichts verkehr machen wenn ich new und delete verwende?
Wie schon dargelegt wurde kannst du vieles verkehrt machen. Wie du deinen Mainframe als "richtiges" Member (also nicht als Pointer) verwenden kannst wurde ja schon gezeigt. Das ist deutlich sicherer und du kannst vieles nicht verkehrt machen.
-
Hi,
Nukularfüsiker schrieb:
Bin mir nicht sicher ob ich das Problem verstehe, aber ich glaube die Lösung heißt Initialisierungsliste.
class test { public: test(); ~test(); private: IGUIElement _mainframe; };test::test() : _mainframe(this) { }
Das funktioniert leider nicht weil:
error C2259: 'IGUIElement': Instanz von abstrakter Klasse kann nicht erstellt werdenMfG
Scarabol
-
Scarabol schrieb:
Das funktioniert leider nicht weil:
error C2259: 'IGUIElement': Instanz von abstrakter Klasse kann nicht erstellt werdenDas hat dann nichts mit der Entscheidnung pointer vs normaler Member zu tun, sondern damit, dass IGUIElement oder eine seiner Basisklassen eine pur virtuelle Methode enthält und nicht instantiiert werden kann (bzw. nur als Basisklassenobjekt einer Klasse, die die entsprechenden Methoden überschreibt). Die Fehlermeldung wäre dir auch bei der Variante "Pointer + new/delete" gekommen.
-
Alles klar danke an euch alle.
MfG
Scarabol