Const initialisieren
-
Hallo ihr Lieben,
mal eine ganz naive Frage:
Ich habe in Erinnerung, dass die Initialisierungsliste z.B. dazu dient, um const Variablen zu initialisieren, z.B.
class foo { foo():_var(1.0){} double const _var; };
Jetzt ist es aber (seit C++11?) möglich den Wert direkt bei der Variablen anzugeben, also
class foo { double const _var = 1.0; }
Gibt es jetzt einen Grund die eine Methode der anderen vorzuziehen? Gerade im Hinblick auf Trennung von h und cpp Dateien. Denn wenn per Konvention in den cpp definiert wird, dann sollte nach wie vor eine Variable in der Initialisierungsliste des Konstruktors initialisiert werden - oder nicht?
Gruß,
-- Klaus.
-
Die Initialisierungsliste ist nicht nur für konstante Variablen, sondern für alle.
Der Vorteil einer Initialisierungsliste ist, dass jede Instanz einen anderen Wert bekommen kann. Wenn der Wert für alle Instanzen gleich sein soll, kann man die Variable auch gleich statisch machen.
-
-
Member-Initialisierung macht den Code übersichtlicher und kürzer, daher setze ich es ein wenn immer möglich.
Dennoch muss bei Strukturen aufgepasst werden:struct {int foo;} bar = {1}; // ok
struct {int foo = 1;} bar = {1}; // error: could not convert '{1}' from '<brace-enclosed initializer list>' to ...
-
Wurde zwar schon gesagt, aber der Unterschied zwischen
class foo { foo():_var(){} const double _var = 0.1; };
und
class foo { foo():_var(){} static const double _var = 0.1; };
ist wichtig.
Das erst _var wird pro Instanz gespeichert, d.h. jedes foo schleppt die Konstante mit rum. Deshalb sollte da auch sizeof(foo) grösser sein. Das ist nützlich, wenn die Variable im Konstruktor initialisiert wird und sich die gesamte Lebensdauer nicht mehr ändert. Z.B. könnte man in einer 2D-Array-Klasse überlegen, den Pointer konstant zu machen.
Wenn die Konstante aber für alle Instanzen genau die gleiche ist, dann sollte sie statisch sein. Und dann geht auch die Initialisierung im Konstruktor nicht mehr, deshalb stellt sich die Frage nicht.
Per Konvention werden in C++ alle Konstanten auch gleich definiert, wenn sie deklariert werden. Früher machte das noch einen Unterschied, heute sind Compiler schlau genug, die zusammenzufassen, falls sinnvoll.
-
Klaus82 schrieb:
Gibt es jetzt einen Grund die eine Methode der anderen vorzuziehen? Gerade im Hinblick auf Trennung von h und cpp Dateien. Denn wenn per Konvention in den cpp definiert wird, dann sollte nach wie vor eine Variable in der Initialisierungsliste des Konstruktors initialisiert werden - oder nicht?
Wenn die Variable in vielen ( aber nicht in allen) Konstruktors gleich initialisiert wird hat die C++11 Methode den Vorteil, dass man weniger Schreibarbeit hat, weil man die Initialisierung nicht in vielen Konstruktors gleich wiederholen muss. Ähnliches kann man mit C++1 aber oft auch mit delegating constructors erreichen.
-
Klaus82 schrieb:
class foo { foo():_var(1.0){} double const _var; };
Mal am Rande gefragt: Warum willst du ein const-Element? Ich kann mich nicht daran erinnern, das jemals gemacht zu haben.
-
krümelkacker schrieb:
Mal am Rande gefragt: Warum willst du ein const-Element? Ich kann mich nicht daran erinnern, das jemals gemacht zu haben.
Zum Einen will ich Naturkonstanten - wie der Name sagt - auch als konstant implementieren.
Und zum Anderen dachte ich, dass es guter Prammierstil wäre: Wenn ich vorher abschätzen kann, dass sich der Wert von Variablen nicht mehr ändert im Programm, dann sollte ich sie zum Selbstschutz als const initialisieren - denn wenn aus Versehen der Wert der Variable überschrieben werden würde, liefert das einen Fehler.
Gruß,
-- Klaus.
-
Soweit so gut, aber warum braucht jedes Objekt seine eigene Naturkonstante? -> static
-
nwp3 schrieb:
Soweit so gut, aber warum braucht jedes Objekt seine eigene Naturkonstante? -> static
Ja, das stimmt schon.
Darüber hatte ich bisher auch noch nicht nachgedacht, weil ich i.d.R. 'ein' Objekt initialisiere, dass dann inhaltlich für die zu berechnende Physik verantwortlich ist. Ich initialisiere also gar nicht mehrere Objekte der gleichen Klasse.
Gruß,
-- Klaus.
-
krümelkacker schrieb:
Mal am Rande gefragt: Warum willst du ein const-Element? Ich kann mich nicht daran erinnern, das jemals gemacht zu haben.
Ich habe so etwas z.B. gebraucht für Objekte, welche eine feste ID oder Namen haben, welche nicht mehr geändert werden darf.
-
Deswegen musst du die Membervariable nicht konstant machen, sondern kannst einfach keinen Schreibzugriff anbieten.
Das Problem ist, dass
const
-Member das Objekt sehr stark einschränken und du Wertsemantik verlierst. Du kannst keine Zuweisungen mehr machen, die Objekte nicht in Containern speichern, ...
-
Klaus82 schrieb:
Darüber hatte ich bisher auch noch nicht nachgedacht, weil ich i.d.R. 'ein' Objekt initialisiere, dass dann inhaltlich für die zu berechnende Physik verantwortlich ist. Ich initialisiere also gar nicht mehrere Objekte der gleichen Klasse.
Physik berechne ich idR mit Funktionen (zumindest im Interface) und verstecke die Konstanten in einem anonymen Namespace im Source-File. Aufgabentrennung ist ein wichtiges Prinzip und ich trenne gerne die Implementierung der Formeln von dem Speichern der Objekte.
-
Nexus schrieb:
Deswegen musst du die Membervariable nicht konstant machen, sondern kannst einfach keinen Schreibzugriff anbieten.
Innerhalb der Klasse kann man auch ohne "Schreibzugriff anbieten" schreiben. Man schützt sich durch das const dagegen sich selbst in den Fuss zu schiessen.
Und es dokumentiert auch gleichzeitig dass sie an den Variablen nie was ändert.Nexus schrieb:
Das Problem ist, dass
const
-Member das Objekt sehr stark einschränken und du Wertsemantik verlierst. Du kannst keine Zuweisungen mehr machen, die Objekte nicht in Containern speichern, ...Wertsemantik "verliert" man nur, wenn das Objekt überhaupt Wertsemantik haben könnte.
Und man verliert move.
Kann man aber oft verschmerzen.Und in gewissen Fällen verliert man genau gar nix, nämlich wenn die Objekte typischerweise so verwendet werden dass man Zeiger auf sie hat. Dann kann man nämlich eh nimmer moven, weil die Stellen die die Zeiger haben das ja nicht mitbekommen.
-
staticonst schrieb:
Physik berechne ich idR mit Funktionen (zumindest im Interface) und verstecke die Konstanten in einem anonymen Namespace im Source-File. Aufgabentrennung ist ein wichtiges Prinzip und ich trenne gerne die Implementierung der Formeln von dem Speichern der Objekte.
Aha. Und wie geht das?
Gruß,
-- Klaus.
-
Beispiel:
// Header: double sqrdist(point p1, point p2); double distance(point p1, point p2); // slow double force(double m1, point p1, double m2, point p2); // Source: // Anonymer Namespace: Diese Konstanten/Funktionen sind nur in diesem File sichtbar namespace { const double G = 6.67384e-11; // Hilfsfunktionen kommen auch rein // (gut, diese könnte man auch als Template öffentlich // machen, aber soll ja nur ein Beispiel sein) double square(double x) { return x*x; } } double sqrdist(point p1, point p2) { return square(p1.x-p2.x) + square(p1.y-p2.y); } double distance(point p1, point p2) { return sqrt(sqrdist(p1, p2)); double force(double m1, point p1, double m2, point p2) { return G*m1*m2/sqrdist(p1, p2); }
-
nwp3 schrieb:
Soweit so gut, aber warum braucht jedes Objekt seine eigene Naturkonstante? -> static
Weil das umschliessende Universum eines Objekts verschieden sein kann.
-
Die Feinstrukturkonstante Alpha hat sich über die Jahrtausende verändert. Damit muss jedes Objekt seine eigene (auf seine Zeit und seinen Raum zutreffende) Feinstrukturkonstante speichern, oder nicht?
-
Und wenn es sich um ein Spiel/Simulation handelt, dann kann es auch ganz interessant sein, wenn Physik fuer manche Objekte unterschiedlich ist.