Philosophie von C++: Objekte so lokal wie möglich zu halten und so spät wie möglich zu definieren
-
Guten Abend
Ausgangspunkt: Man habe z.B. viele Zeilen (min. 1 Mio) aus einer Datei gelesen und will nun jede Zeile mit einem Objekt verarbeiten und dieses in einem Container ablegen.
Nun frage ich mich gerade, welche der 3 Varianten man bevorzugt nehmen sollte. Die Philosophie von C++ ist doch, Objekte so lokal wie möglich zu halten und so spät wie möglich zu definieren. Demnach fällt Variante 1 schon mal weg, da
f
in der kompletten Funktion zur Verfügung steht, es aber nur für die Schleife gedacht ist. Bei Variante 2 und 3 wird der Scope extra so festgelegt, dassf
nur für die Schleife zur Verfügung steht und danach wieder zerstört wird.Ich persönlich finde Variante 2 ganz schön, da ich es bei Variante 3 absurd finde, in jedem Schleifendurchgang ein Objekt zu erstellen und zu zerstören; das schlägt doch bestimmt auch auf die Performace aus, oder? Von welcher Variante haltet ihr am meisten?
/* Variante 1 */ int main() { vector<Foo> vec; Foo f; for(int i=0; i!=1000000; ++i) { // Verarbeitung von f... vec.push_back(f); } } /* Variante 2 */ int main() { vector<Foo> vec; { Foo f; for(int i=0; i!=1000000; ++i) { // Verarbeitung von f... vec.push_back(f); } } } /* Variante 3 */ int main() { vector<Foo> vec; for(int i=0; i!=1000000; ++i) { Foo f; // Verarbeitung von f... vec.push_back(f); } }
-
Ehrlich gesagt seh ich da keinen nennenswerten Unterschied zwischen 2 und 3, außer dass 2 vielleicht sinnlos ist.
Wieso aber willst du schon vor Programmablauf festlegen, wie groß die Datei ist?
-
Beispiel zu abstrakt.
Vermutlich ist Variante 3 am besten.
Kann es aber mit Foo nicht genau sagen.
-
Ich sehe keinen relevanten Unterschied zwischen Variante 1 und 2.
@Volkard: wird dadurch aber der Konstruktor und Destruktor nicht unnötig bei jedem Schleifendurchlauf aufgerufen?
-
Hacker schrieb:
Ehrlich gesagt seh ich da keinen nennenswerten Unterschied zwischen 2 und 3, außer dass 2 vielleicht sinnlos ist, da - wenn du einen Vector mit Foos hast, dieses Foo natürlich in der for(;;)-Schleife stehen kann.
Jup, dann habe ich in aber das ständige "Objekt erzeugen, Objekt zerstören".
Hacker schrieb:
Wieso aber willst du schon vor Programmablauf festlegen, wie groß die Datei ist?
Das sollte jetzt nur als Beispiel dienen.
Also, worauf ich hinaus wollte ist, wenn ein Objekt nur für eine Schleife gedacht ist, dann sollte man es auch so deklarieren, dass es nur für die Schleife benutzt werden kann.
-
Naja, wenn man beispielsweise in einer Schleife getline() aufruft, sollte man den Zielstring außerhalb definieren, sonst kommt das echt teuer.
-
[Rewind] schrieb:
Ich sehe keinen relevanten Unterschied zwischen Variante 1 und 2.
Ich schon. Bei Variante 1 kann ich Foo f in der kompletten Funktion verwenden. Bei Variante 2 nur für die Schleife. Bezüglich des C++-Paradigmas ist das für mich also ein großer Unterschied. :p
-
Probier's doch einfach aus? (Und schreib am besten mal ein etwas ausführlicheres Beispiel.)
-
Man kann es ja auch anders machen, folgende Schleife fänd ich toll:
for(Foo temp();!DeinStream.eof();vec.push_back(temp)) //Dein Zeug
-
Gugelmoser schrieb:
[Rewind] schrieb:
Ich sehe keinen relevanten Unterschied zwischen Variante 1 und 2.
Ich schon. Bei Variante 1 kann ich Foo f in der kompletten Funktion verwenden. Bei Variante 2 nur für die Schleife. Bezüglich des C++-Paradigmas ist das für mich also ein großer Unterschied. :p
Achso, wenn die Funktion noch weitergeht, dann natürlich ja, aber ich bezog mich nur auf das Beispiel. Sorry, muss den Satz im ersten Beitrag übersehen haben.
-
edit: gelöscht
-
Hacker schrieb:
for(Foo temp;!DeinStream.eof();vec.push_back(temp)) //Dein Zeug
Stimmt, ist aber ja letztendlich dasselbe wie in Variante 2. Du erzeugst temp nur 1x, verarbeitest es in der Schleife und legst es am Ende im Container ab.
Hier habe ich mal noch ein Beipsiel.
#include <string> #include <fstream> #include <vector> using namespace std; class CSNP { private: string snpName; string allele1; string allele2; public: friend istream& operator>>(istream& in, CSNP& csnp) { getline(in,csnp.snpName,' '); getline(in,csnp.allele1,' '); return getline(in,csnp.allele2); } }; int main() { ifstream in("foo.bar"); // min. 1Mio Zeilen. if(!in) return -1; vector<CSNP> objects; for(CSNP csnp; in >> csnp;) // Wäre ja nun Variante 2. { objects.push_back(csnp); } // ab hier geht es dann mit dem Vector weiter, etc. }
-
Edit: wieder gelöscht
-
Hm.. was man machen könnte, wäre einen CSNP Konstruktor zu definieren, der einen std::istream& nimmt und seine Sachen selbst einliest. Damit würde das zu
for (so viele Zeilen wie ich will) objects.push_back(CSNP(in)); // Wirft exception
werden.
Falls du aber einfach "lesen bis zum Ende" möchtest, ist die for-Schleife doch eigentlich gut. Eventuell noch mit Move-Konstruktor für CSNP.
-
Hacker schrieb:
Man kann es ja auch anders machen, folgende Schleife fänd ich toll:
for(Foo temp();!DeinStream.eof();vec.push_back(temp)) //Dein Zeug
Und ist doppelt Falsch. Korrekt:
for(Foo tmp; stream; vec.push_back(tmp)) stream >> tmp;
-
Korrekter:
for(Foo tmp; stream >> tmp; vec.push_back(tmp));
-
Hacker schrieb:
Ehrlich gesagt seh ich da keinen nennenswerten Unterschied zwischen 2 und 3, außer dass 2 vielleicht sinnlos ist.
Wieso aber willst du schon vor Programmablauf festlegen, wie groß die Datei ist?Der Unterschied zwischen 2 und 3 ist, dass bei Variante 3 das Ding pro Schleifendurchlauf neu erstellt wird.
Ich würde das schon als nennenswert bezeichnen.
-
314159265358979 schrieb:
Hacker schrieb:
Man kann es ja auch anders machen, folgende Schleife fänd ich toll:
for(Foo temp();!DeinStream.eof();vec.push_back(temp)) //Dein Zeug
Und ist doppelt Falsch. Korrekt:
for(Foo tmp; stream; vec.push_back(tmp)) stream >> tmp;
upseldidupseldi. Die Klammern hab ich aus versehen reingemacht :p
-
Die Klammern waren ja auch unwichtig.
-
cooky451 schrieb:
Die Klammern waren ja auch unwichtig.
Dann war aber nur eine Sache "Falsch".