Bin ich eigentlich der einzige, der sowas macht?
-
doch nicht. sorry.
-
ich benutz die memberinitialisierung mittels new nur dann, wenn ich nen basisklassen zeiger hab, der über ein template seine abgeleitete Klasse bekommen soll...
-
@otze: Ja, das ist bei mir jetzt genau eben nicht der Fall, deshalb frage ich.
@KdeE: Ich benutze aber nicht die nothrow-Variante
Ob es jetzt sinnvoll ist, diese Exception überhaupt abzufangen (ich glaub in meinem Fall wäre dann schon alles zu spät, wenn das nicht mehr hinhaut), sei dahingestellt. Die Referenz ist aber sicher nicht NULL.
-
hat die memberklasse nen besonders überladenen new operator?
-
Nein, es ist nichts besonderes, ich mach das nur wegen der Header-Datei. Und natürlich auch nur, wenn es Performance-mäßig nicht relevant ist. Ich spare mir dadurch etliche folge-includes, weil die Foo-Header dann von vielen anderen Dateien noch inkludiert wird.
-
Optimizer schrieb:
// Header-Datei class Foo { ... SomeClass& member; }; // Source-Datei Foo::Foo() : member( *(new SomeClass()) ) {} Foo::~Foo() { delete &member; }
Hat das irgendwelche gravierende Nachteile gegenüber
SomeClass member;
??
- Die Klasse ist standardmäßig kopierbar (wenn auch nicht zuweisbar) mit komischem Verhalten.
- Eine Referenz zu deleten ist unüblich und damit verwirrend für arme Codeleser.
- Und wenn du zwei Member so initialisierst, sieht es mit der Exceptionsicherheit mau aus - wie fast immer, wenn man delete selber aufruft.Das fällt mir so spontan ein
-
Punkt 1 ist mir natürlich vollkommen klar. In meinem Fall sind die Objekte aber sowieso standardmäßig nicht kopierbar.
-
Also ich wuerde sowas der besseren Lesbarkeit halber mit einem auto_ptr realisieren..
-
Wenn man einen guten Tag hat:
class Foo { boost::scoped_ptr<SomeClass> ptr; SomeClass& member; ... }; Foo::Foo() : ptr(new SomeClass), member(*ptr) { }
Kostet wahrscheinlich etwas mehr Speicher, aber was solls, wir haben's ja :p
-
Also jetzt muss ich doch mal Optimizer zustimmen. Ich mache auch so etwas, Referenzen im Konstruktor mittels "new" auf einen gültiges Objekt referenzieren zu lassen und in Destruktor wieder zu löschen.
Was spricht dagenen? Es gibt zwischen Pointern und Referenzen keinen Unterschied, ausser dass man mal mit "." und mal mit "->" die Elemente anspricht. Und das eine Referenz nicht Null sein kann, stimmt ja auch nicht,int &i(* ((int*)0) ); if(&i == 0) then std::cout << "&i == 0" << std::endl; else std::cout << "Schmeiss Deinen Rechner weg!" << std::endl;
Vielmehr geht es bei Referenzen darum, dass man davon ausgehen sollte, dass sie auf etwas gütliges zeigen. Optimizer hätte dies auch mit pointern machen können, würde dann nichts daran ändern, dass bei einem Fehlgeschlagenen new einmal der Pointer null ist bzw. sonst die Adresse hinter der Referenz. Wenn es darum geht sich die ganzen Includes zu sparen, aber die Objekte im jeden Fall initialisert sein "sollen", quasi so als ob man sie "by value" als Klassenelemente definiert hätte, ist es von der Semantik in meinen Augen korrekter Referenzen zu verwenden, anstatt Pointern. Einen Pointer muss man halt vor JEDER Verwendung auf NULL hin überprüfen, von einer Referenz geht man davon aus, dass sie gültig ist. Wenn man es dann ganz genau nimmt, müsst man also im Konstruktor nach dem new noch überprüfen, ob dies nicht fehltgeschlagen ist und dann evtl. selber eine Exception werfen - aber sonst wird nirgendwo mehr die Adresse überprüft.
-
standard new wirft ja selber ne exception wenns fehlschlägt,entweder man fängt sie ab, oder man lässt sie durch, beide male sollte das programm beendet werden,weil eh alles verlorenb ist, wenn sogar new schon fehlschlägt
-
wischmop2 schrieb:
Und das eine Referenz nicht Null sein kann, stimmt ja auch nicht
Doch. Dein Code hat undefiniertes Verhalten. Bitte fang keine Diskussion dazu an, das hatten wir hier schon mindestens einmal zu oft. Mach dich im Standard schlau.
Einen Pointer muss man halt vor JEDER Verwendung auf NULL hin überprüfen
Warum? Man überprüft natürlich nur dann auf einen Nullpointer, wenn man von der Programmlogik her nicht davon ausgehen kann, dass er garantiert nicht 0 ist. Dass die Programmlogik stimmt kann man mit Assertions sicherstellen.
Wenn man es dann ganz genau nimmt, müsst man also im Konstruktor nach dem new noch überprüfen, ob dies nicht fehltgeschlagen ist und dann evtl. selber eine Exception werfen - aber sonst wird nirgendwo mehr die Adresse überprüft.
Wenn new fehlschlägt, wirfst es schon eine Exception. Vielleicht benutzt du einen veralteten Compiler, wo das nicht der Fall ist ... in dem Fall hättest du natürlich Recht. Wenn die Objektkonstruktion fehlschlägt, sollte eine Exception geworfen werden, ein halbfertiges Objekt nützt ja niemandem was.
-
Optimizer schrieb:
Mach ich ab und zu mal, damit ich in der Header nicht die SomeClass-Header inkludieren muss. Da ich es eigentlich noch nirgendwo anders gesehen habe, muss es wohl keine gute Idee sein.
ja, die idee ist scheiße.
-verwende zeiger, wenn du zeiger meinst!
-das new dauernd ist schneckenlahm.
-kannst locker auf andere wege impls verstecken. mußt halt den mut haben, auch mal ne non.standard-zeile zu schreiben und dann dem sutter nicht alles glauben.
-
-verwende zeiger, wenn du zeiger meinst!
Ich meine aber nicht Zeiger. Das ist eine Komposition, das SomeClass gehört fest zu dem Foo, von dem es konstruiert wird.
-kannst locker auf andere wege impls verstecken. mußt halt den mut haben, auch mal ne non.standard-zeile zu schreiben und dann dem sutter nicht alles glauben.
Den Mut dazu hab ich schon. Jetzt muss ich nur noch wissen, wie?
-
Bashar schrieb:
Dein Code hat undefiniertes Verhalten. Bitte fang keine Diskussion dazu an, das hatten wir hier schon mindestens einmal zu oft. Mach dich im Standard schlau.
Gut, will jetzt hier nicht mit Programmbeispielen kommen, die eh nichts darüber sagen, wie es der Standard vorsieht, sondern nur etwas darüber sagen würden, was ein Compiler damit macht. Aber vielleicht kannst Du mir mal einen Link zum Standard geben, wo das beschrieben ist was Du sagst. Habe in Büchern nämlich immer nur gelesen, dass man das mich machen soll. Oder habe ich Dich mit "undefiniertem Verhalten" falsch verstanden? Darf man etwa eine Referenz nicht mit dem Inhalt (in wirklichkeit ja dann doch der Adresse) eines Pointers initialisieren? Dass man auf die Elemente nicht zugreifen darf, wenn der Pointer auf die Adresse 0 (oder von meinetwegen auch NULL) zeigt ist klar, aber das gilt halt auch für Pointer. (Es sei denn, das NULL auf eine Sentinel-Instanz zeigt, aber dann gilt dies auch für die Referenz). Also, will darüber nicht diskutieren, nur ein Verweis, wo ich dies selber nachlesen kann, würde mich freuen, damit ich soetwas nicht mehr mache - auch wenn's Funktioniert.
Bashar schrieb:
Warum? Man überprüft natürlich nur dann auf einen Nullpointer, wenn man von der Programmlogik her nicht davon ausgehen kann, dass er garantiert nicht 0 ist. Dass die Programmlogik stimmt kann man mit Assertions sicherstellen.
Was meinst Du mit "Assertions sicherstellen" ? Etwa falls p ein Pointer ist, von dem man nicht weiss ob er gültig ist, so etwas ?
assert(p); p->foo();
Naja, das wäre ja eine Überprüfung. Ich meine eigentlich nur, dass man von einer Referenz davon ausgehen kann (sollte), dass sich dahinter etwas gütiges verbirgt, Du hast ja selber geschrieben, dass eine Referenz mit NULL nach Standard strunz ist - wo ich Dir ja auch zustimme. Wenn ich aber einen fremden Code verwende, weiss ich bei einem Pointer eben nicht (sofern es nicht irgend wo dokumentiert ist), dass ein Pointer gültig ist und deshalb meinte ich, dass ich dies überprüfen muss, im Gegensatz zur Referenz.
Bashar schrieb:
Wenn new fehlschlägt, wirfst es schon eine Exception. Vielleicht benutzt du einen veralteten Compiler, wo das nicht der Fall ist ... in dem Fall hättest du natürlich Recht. Wenn die Objektkonstruktion fehlschlägt, sollte eine Exception geworfen werden, ein halbfertiges Objekt nützt ja niemandem was.
Ack - zuvor wurde nur etwas von einer "nothrow-Variante" geschrieben - wollte nur diesen Fall mit abdecken.
Last but not least - mir ist nun nicht klar, was gegen Optimizers Methode spricht, Referenzen als Membervariablen zu verwenden?
-
Nur um das mit den Null Referenzen nochmal zu klären. Im Stroustrup (3.Aufl.) Steht in Kapitel 15.4.1.1 "dynamic_cast von Referenzen"
"Um ein polymorphes Verhalten zu erreichen , muss ein Objekt über einen Zeiger oder eine Referenz manipuliert werden. Wenn ein dynamic_cast für einen Zeigertyp benutzt wird, bedeutet 0 einen Fehler. Das ist bei Referencen weder möglich noch erwünscht."
und dann gehts weiter dass die stattdessen einen bad_cast werfen.
mfg, KdeE
-
Das dereferenzieren eines NULL-Zeigers erzeugt undefiniertes Verhalten. Und das machst du ja hier.
int &i(* ((int*)0) );
-
Dann besteht aber nach dem, was bisher gesagt wurde, kein Unterschied zwischen NULL-Zeiger und NULL-Referenzen. *einmisch*
Trotzdem sorge ich natürlich dafür, dass Referenzen bei mir nicht NULL sind, das widerspricht meiner Intuition.
-
Mal ne frage nebenbei: Hier ist dauernd die rede von Exception abfangen. Wie soll das gehen?
catch in der initialisierungsliste "rethrowed" automatisch, falls keine andere Exception geworfen wird. Ein Abfangen ist deshalb gar nicht möglich. ODer bin ich da falsch informiert.
-
a) new ausserhalb fangen
b) kein new in die initialisierungsliste