[STL] Vector iterator an Position springen
-
Edit:
SeppJ schrieb:
Dadurch, dass du deine Klassen nicht sauber designed hast [..]
Ich nehme an du meinst die Regel der Großen Drei?
SeppJ schrieb:
[..] du selber manuelle Speicherverwaltung probiert hast (ohne es zu können)
Was genau bezeichnest du als manuelle Speicherverwaltung? Die Anwendung von Zeigern und / oder Referenzen?
Gruß,
Klaus.
-
Kann
size
in Zeile 11 0 werden?
Sonst bau dir doch ein paar Debug Ausgaben in deine Funktion ein, die Auskunft darüber geben, was passiert. Das VS hat z.B. das TRACE Makro, sowas kann man sich zur Not auch noch selbst basteln. Damit brauchst du nicht ewig mit dem Debugger durch dutzende Schleifendurchläufe zu gehen, sondern kannst dir den Inhalt verschiedener Variablen bis zu dem Punkt wo´s knallt ausgeben lassen.
-
Klaus82 schrieb:
unsigned int position = (*p_random)() * (size - 1);
Unter der Annahme, dass p_random gleichverteilte Fließkommazahlen zwischen 0 und 1 generiert, geht die Gleichverteilung durch diese Rechnung verloren. size - 1 wird wesentlich weniger häufig vorkommen als alle anderen Werte.
Diese Fließkommarunderei verkompliziert die ganze Angelegenheit deutlich - selbst wenn du sicherstellst, dass p_random im Intervall [0, 1) statt [0, 1] generiert, kannst du nicht sicher sein, dass p_random() * size nicht size wird - Rundungsfehler halt. Es wäre besser, einen Zufallszahlengenerator zu benutzen, der gleich Integer ausspuckt und ihn durch std::uniform_int_distribution zu pressen.
-
DocShoe schrieb:
Kann
size
in Zeile 11 0 werden?
Sonst bau dir doch ein paar Debug Ausgaben in deine Funktion ein, die Auskunft darüber geben, was passiert.Puh, ja. Ich versuche gerade debuggen zu lernen und finde diese Kurzanleitung ganz gut.
Ich habe das ganze mit einer core Datei probiert und dann Backtrace.
. .. ... Program terminated with signal 11, Segmentation fault. [New process 5100] #0 0x00000000004060de in AUGER::auger_process () (gdb) bt #0 0x00000000004060de in AUGER::auger_process () #1 0x000000000040370c in main () Current language: auto; currently asm
Also schon ein guter Hinweis darauf, dass es an dem liegen muss was in auger_process() passiert.
seldon schrieb:
Klaus82 schrieb:
unsigned int position = (*p_random)() * (size - 1);
Unter der Annahme, dass p_random gleichverteilte Fließkommazahlen zwischen 0 und 1 generiert, geht die Gleichverteilung durch diese Rechnung verloren. size - 1 wird wesentlich weniger häufig vorkommen als alle anderen Werte.
Also ich habe mal (das Debuggen lerne ich ja noch) ganz naiv eine Ausgabe implementiert:
unsigned int size = r_electrons.size(); unsigned int position = (*p_random)() * (size - 1); cout << "Size : " << size << " vs. position : " << position << endl; r_electrons[position].energy = r_electrons[position].energy + transfered_energy;
Und heaus kam jetzt folgendes:
Size : 0 vs. position : 1872372286 Speicherzugriffsfehler (core dumped)
EDIT:
Na klar, weil ich size -1 eingebaut habe.
D.h. wenn size gerade 1 ist, dann knallt es eben! Baue ich also wieder aus.Also das wundert mich jetzt doch. Vor allen Dingen weil ich vorher eine if Abfrage drin habe
if(electrons.size() > 0)
Also diese Funktion dürfte gar nicht ausgeführt werden, wenn electrons.size() Null ist!
Aber ich habe ja noch eine andere starke Vermutung, wo wahrscheinlich reinspielt, dass ich keinen Destruktor definiert habe (also schlechtes Klassendesign).
Grob habe ich (leicht erweitert) die Struktur:
vector<electron> electrons; vector<electron> & r_electrons = electrons; for(int k = 0; k < 1000; ++k) { for(int n = 0; n < 10; ++n) { electrons.push_back(...) } for(unsigned int i = 0; i < electrons.size(); ++i) { // .. stuff auger.auger_process(r_electrons,i); // .. stuff } electrons.clear(); }
Also ich definiere einmal die Referenz auf meinen Vektor. Allerdings leere ich meinen Vektor öfters, d.h. ich rufe eigentlich Destruktoren auf, die ich aber in der Klasse nicht explizit definiert habe.
Kann es sein, dass dadurch die Adresse (in der Referenz) irgendwie in Mitleidenschaft gezogen wird? In der Beschreibung von clear steht dazu nichts, dass Pointer o.ä. dadurch ungültig würden (wie z.B. bei erase() aber das bezieht sich dann ja wieder auf Pointer auf das gelöschte Element).Oh man ...
Gruß,
Klaus.
-
Klaus82 schrieb:
Ich meine ich habe eine große for Schleife:
vector<electron> electrons; vector<electron> & r_electrons = electrons; for(unsigned int i = 0; i < electrons.size(); ++i) { // .. stuff auger.auger_process(r_electrons,i); // .. stuff }
Die Referenz ist da unnötig; denn der Ausdruck
electrons
hat denselben Typ und dieselbe Wertkategorie wie der Ausdruckr_electrons
. Dass lezteres als Referenz deklariert war, merkt die Funktion gar nicht. Es beeinflusst auch nicht die Überladungsauflösung. Ausdrücke haben nie einen Referenztypen.Klaus82 schrieb:
Mit der Klassenfunktion:
void AUGER::auger_process(vector<electron> & r_electrons, unsigned int i) { if(r_electrons[i].energy > 5 || (*p_random)() > auger_probability(r_electrons[i].energy) ) { return; } double transfered_energy = r_electrons[i].energy + ionization_potential(4); r_electrons.erase(r_electrons.begin()+i); unsigned int size = r_electrons.size(); unsigned int position = (*p_random)() * (size - 1); r_electrons[position].energy = r_electrons[position].energy + transfered_energy; return; }
Und ich kriege immer dann einen Speicherzugriffsfehler, wenn ich diese Klassenfunktion ausführe.
Maaaan, so schief programmiert ist das doch hoffentlich nicht - auch wenn natürlich schon 'ein-wenig-schief' reicht.Das sieht schon komisch aus. Wenn man sich die äußere Schleife anguckt, denkt man: die geht über alle Elemente rüber, aber, hinterhältig wie du bist, veränderst du die Größe des vektors innerhalb der Funktion.
Das
*(size-1)
ist auch nicht richtig. Jedenfalls dann nicht, wenn Du eine Gleichverteilung haben willst. Bedenke auch, dass die implizite Umwandlung die Nachkommastellen einfach abschneidet.size
ist also richtig als Faktor, wenn man annimmt, dass die Zufallszahl aus [0,1) gezogen wird. Sollte da doch dann mal eine 1.0 dabei sein oder Rundungsfehler auftreten, iststatic_cast<unsigned>((*p_random)() * size) % size
wahrscheinlich die beste Idee, sofern Du es unbedingt mit p_random machen willst.
-
krümelkacker schrieb:
Die Referenz ist da unnötig; denn der Ausdruck
electrons
hat denselben Typ und dieselbe Wertkategorie wie der Ausdruckr_electrons
. Dass lezteres als Referenz deklariert war, merkt die Funktion gar nicht. Es beeinflusst auch nicht die Überladungsauflösung. Ausdrücke haben nie einen Referenztypen.Aber ich dachte das brauche ich genau dafür:
krümelkacker schrieb:
Das sieht schon komisch aus. Wenn man sich die äußere Schleife anguckt, denkt man: die geht über alle Elemente rüber, aber, hinterhältig wie du bist, veränderst du die Größe des vektors innerhalb der Funktion.
Wenn ich keinen Pointer oder Referenz übergebe, so mache ich doch Call bei Value, also es wird eine lokale Kopie angelegt. Das Problem bei Call by Value ist doch aber, dass die lokale Kopie bearbeitet wird und Änderungen daran keine Auswirkungen auf das ursprüngliche Objekt haben.
So dachte ich, dass mein Vektor dementsprechend nicht bearbeitet wird, wenn ich das ganze nicht als Referenz übergebe.Aber nochmal:
krümelkacker schrieb:
Das sieht schon komisch aus. Wenn man sich die äußere Schleife anguckt, denkt man: die geht über alle Elemente rüber, aber, hinterhältig wie du bist, veränderst du die Größe des vektors innerhalb der Funktion.
Was genau ist daran komisch? Dafür ist doch der Vektor zum Glück dynamisch. Oder wie macht man das 'professionell' ? Während ich die einzelnen Elemente durchgehe, kann welche wegnehmen, hinzufügen oder modifizieren.
Oder nachdem ich SeppJ Link gesehen habe 'merkt' man sich diese Elemente beim Durchgang und tut nach dem Durchgang entsprechend hinzufügen und löschen?
Gruß,
Klaus.
-
Also ich habe nochmal über diese Problemstellung nachgedacht, zum Einen das Verändern der Länger des Vektors, während er durchlaufen wird und zum Zweiten die Anwendung von Erase remove Idiom.
Zum ersten Punkt sehe ich ein, dass es sicherlich komisch ist die Länge eines Arrays zu ändern, während man ihn durchläuft - aber wie ich schon sagte, dafür ist es doch ein dynamisches Objekt?
Ich durchlaufe den Vektor mehrmals und durch Zufallszahlen bedingt ergibt sich bei jedem Durchlauf und für jedes Element individuell, ob es gelöscht wird oder nicht.Und so verstehe ich auch nicht so recht, wie dieser Algorithmus des Löschens so recht funktionieren soll.
Ich würde meinen Vektor durchlaufen und jedes Mal, wenn sich ergibt, dass ein Element gelöscht werden soll, bekommt es sagen wir int remove = 1 gesetzt (vorher remove = 0).Und anschließend (!) lasse ich den Algorithmus drüberlaufen, der alle Elemente mit remove = 1 nach hinten schiebt, um sie dann zu löschen?
Da würde ich ja zwei Mal meinen Vektor durchlaufen!So frage ich mich natürlich direkt umgekehrt, ob ich meine Elemente nicht individuell löschen soll, sondern erstmal ans Ende schieben, um sie anschließend alle zu löschen. Das wäre dann scheinbar ein Kompromiss aus meiner bisherigen Lösung un dem Erase remove Idiom.
Nein wäre es nicht, denn Elemente in einem Vektor zu verschieben ist ziemlich umständlich.
Ich brauche den Vektor bisher eigentlich nur, weil ich auf ein beliebiges Element daraus zugreifen möchte. Ansonsten würde mir ja eine Liste oder ein Set völlig reichen.!Ansonsten bin ich natürlich für vollkommen neue Sichtweisen dankbar.
Viele Grüße,
Klaus.
-
Klaus82 schrieb:
So frage ich mich natürlich direkt umgekehrt, ob ich meine Elemente nicht individuell löschen soll, sondern erstmal ans Ende schieben, um sie anschließend alle zu löschen. Das wäre dann scheinbar ein Kompromiss aus meiner bisherigen Lösung un dem Erase remove Idiom.
Nein wäre es nicht, denn Elemente in einem Vektor zu verschieben ist ziemlich umständlich.
Ich brauche den Vektor bisher eigentlich nur, weil ich auf ein beliebiges Element daraus zugreifen möchte. Ansonsten würde mir ja eine Liste oder ein Set völlig reichen.!Ansonsten bin ich natürlich für vollkommen neue Sichtweisen dankbar.
Wenn Du Elemente löscht, müssen die verbleibenden Elemente meines Wissens auch verschoben werden.
Zusätzlich denke ich mir, daß beim Löschen von Elementen jedes Element
einzeln gelöscht werden muß.Verschiebt man allerdings erst die Elemente ans Ende und löscht dann, kann man "alle aufeinmal" löschen.
Je nach Anzahl der Elemente, die gelöscht werden sollen, kann das effektiver sein.
-
seldon schrieb:
Diese Fließkommarunderei verkompliziert die ganze Angelegenheit deutlich - selbst wenn du sicherstellst, dass p_random im Intervall [0, 1) statt [0, 1] generiert, kannst du nicht sicher sein, dass p_random() * size nicht size wird - Rundungsfehler halt.
Sofern size nicht mehr signifikante Bits hat als die Mantisse der Zufallszahl (also typischerweise 53 bit für double), sollte das nicht passieren. Und falls size größer ist, kann sowieso nicht jede Ganzzahl im relevanten Intervall entstehen - dann muss ohnehin anders vorgegangen werden.
-
Also ich habe mit meinen begrenzten C++ Fähigkeiten noch einmal über diese Problematik nachgedacht.
Soweit ich das überblicke stehen die beiden Anfordungen kontraproduktiv gegenüber:
Zum Einen möchte ich einen Indexzugriff, zum anderen auch beliebige dynamisch Elemente löschen könnenVon meinem Verständnis her sind die Elemente in vector komplexer angelegt, als z.B. in einer Liste. Dort kennt jedes Element ja nur seinen Vordermann und Nachfolger.
Um einen Indexzugriff zu ermöglichen benötige ich weitere Informationen, um das Element n schnell finden zu können.Und das ist auch das Problem beim Löschen. Wenn ich nun das Element n löschen will, so muss ich die komplexe Anordnung des vectors aufbrechen, das Element löschen und anschließend müssen die übrigen Elemente neu angeordnet werden, um wieder schnellen Indexzugriff zu erlauben.
Bei einer Liste geht das ganze schneller, da ich lediglich die Adressen des Vordermanns und Nachfolger entsprechend vergeben muss. Also der Nachfolger des Elements wird der Nachfolger des Vordermanns und vice versa. Nicht viel Aufwand.
Jetzt habe ich bei meinem vector zwei Möglichkeiten die ganzen Elemente zu durchlaufen:
Index:
for(unsigned int i = 0; i < vector.size(); ++i) { vector[i] // do something }
Jetzt muss ich beim Löschen eines Elements natürlich auf den Index i aufpassen. Also wenn ich mit der Zeit beim Index i = 17 angekommen bin und entscheide, dass dieses Element gelöscht werden muss, welches Element wird denn dann als nächstes bearbeitet nach dem ++i der for-Schleife?
Spontan würde ich sagen, dass die übrigen Elemente 'nachrutschen', sodass der Nachfolger von i = 17 dann das Element 17 ist. D.h. nach der Aktion ++i wäre ich schon bei i = 18 und hätte somit ein Element übersprungen?Ich hatte auch überlegt, die Indizes der zu löschenden Elemente separat zu speichern, sodass ich anschließend nach dem Durchlauf das Löschen durchführen kann.
Das Problem ist doch dabei wieder nur, sobald ein Element gelöscht ist, sind die ganzen übrigen gespeicherten Indizes falsch, weil die Indexnotation um ein Element verschoben ist.Also auch Müll!
Iterator:
for(vector::iterator iter = vector.begin(); iter != vector.end(); ++iter) { iter // do something }
Hierbei hatte ich mir sogar noch was ganz anderes überlegt, sodass ich sogar komplett auf den Vektor verzichten kann.
Denn während bei der Indexnotation die Problematik das Löschen ist, ist die Problematik bei einer Liste o.ä. eben der fehlende Indexzugriff. Denn ich will eine Eigenschaft eines vorher gelöschten Objekts auf ein zufälliges restliches Objekt verteilen.
Nachdem ich aber bei Listen keinen Indexzugriff habe, kann ich das zufällig bestimmte Element n aber nur finden, indem ich vom Start ausgehend n Element entlangehe - und das dauert!Also habe ich mir überlegt, diese Übertragung auf ein zufällig bestimmtes Element für den nächsten Durchlauf aufzuheben.
Sprich ich lösche ein Element und speichere eine Eigenschaft. Dann bestimme ich ein zufälliges Element, dass diese Eigenschaft erhalten soll und speichere dies in einer separaten Liste (alle Eigenschaften werden sortiert, also nehme ich beser ein Set?)Und beim nächsten Durchlauf läuft ein Zähler mit, der vergleicht ob das aktuelle Element die gleiche Nummer trägt wie das zufällig bestimmte und falls ja - wird die Eigenschaft übertragen.
Damit spare ich mir das mühselige Durchlaufen, um das n. Element zu erreichen, da ich es auf den nächsten Durchlauf verschiebe, wo die ganze Liste sowieso durchgegangen wird.
Vielen Dank an alle, die bis zum Ende gelesen haben.
Viele Grüße,
Klaus.
-
Ich nehme an, dass du nach dem Erase-Remove-Idiom suchst.
-
Hi,
seldon schrieb:
Ich nehme an, dass du nach dem Erase-Remove-Idiom suchst.
das wurde mir auch schon vorgeschlagen und ich hatte es hier kritisch betrachtet.
Mein Problem ist, dass während des Durchlaufs anhand einer Zufallszahl entschieden wird, ob ein Element gelöscht werden muss oder nicht.
Es ist also nicht so, dass ich von vorneherein sagen kann: "Lösche alle Elemente mit 'eigenschaft' = 10".
Gruß,
Klaus.
-
Klaus82 schrieb:
Es ist also nicht so, dass ich von vorneherein sagen kann: "Lösche alle Elemente mit 'eigenschaft' = 10".
Na und? Du kannst doch bei remove_if ein beliebiges Prädikat angeben, z.B. eines, das zufällig true oder false ist.
-
Naja,
std::vector<int> v; v.erase(std::remove_if(v.begin(), v.end(), [](int) { return std::rand() % 10 == 0; }), v.end());
bzw. in C++03
bool is_doomed(int) { return std::rand() % 10 == 0; } ... std::vector<int> v; v.erase(std::remove_if(v.begin(), v.end(), is_doomed), v.end());
-
seldon schrieb:
Naja, [...]
Wenn schon C++11, dann gleich richtig:
std::vector<int> v; v.erase(std::remove_if(begin(v), end(v), [](int) { return std::rand() % 10 == 0; }), end(v));
-
Klaus82 schrieb:
krümelkacker schrieb:
Die Referenz ist da unnötig; denn der Ausdruck
electrons
hat denselben Typ und dieselbe Wertkategorie wie der Ausdruckr_electrons
. Dass lezteres als Referenz deklariert war, merkt die Funktion gar nicht. Es beeinflusst auch nicht die Überladungsauflösung. Ausdrücke haben nie einen Referenztypen.Aber ich dachte das brauche ich genau dafür: [...]
Dann hast du Referenzen noch nicht verstanden.
Klaus82 schrieb:
Wenn ich keinen Pointer oder Referenz übergebe, so mache ich doch Call bei Value, also es wird eine lokale Kopie angelegt.
Dafür musst du aber auf Aufruferseite keine extra Referenz anlegen; denn
void foo(int& ref_in_foo); int main() { int i = 42; int& ref_in_main = i; foo(ref_in_main); }
ist äquivalent zu
void foo(int& ref_in_foo); int main() { int i = 42; foo(i); }
Tatsächlich gibt es da überhaupt keinen Unterschied zwischen der Initialisierung von ref_in_foo und ref_in_main. Du kannst auch 3 Referenzen dazwischen bauen:
void foo(int& ref_in_foo); int main() { int i = 42; int& r1 = i; int& r2 = r1; int& r3 = r2; foo(r3); }
Das spielt alles keine Rolle. Du kannst auch einfach
ref_in_foo
direkt miti
beim Funktionsaufruf initialisieren (wie im zweiten Beispiel).Klaus82 schrieb:
Was genau ist daran komisch? Dafür ist doch der Vektor zum Glück dynamisch.
Es wär halt schön, wenn du um das Löschen einzelner Elemente drum herum kommen würdest. erase-remove hätte ich Dir auch empfohlen, aber ich stimme dir zu, dass das nicht wirklich anwendbar ist, in deinem Fall. Zumindest sehe ich es nicht.
-
1. Iterator auf das letzte Element holen.
2. Wenn ein Element gelöscht werden soll, Element mit *last tauschen.
3. Last erniedrigen
4. Remove & Erase Idiom
-
Hi,
krümelkacker schrieb:
Dann hast du Referenzen noch nicht verstanden.
Dafür musst du aber auf Aufruferseite keine extra Referenz anlegen; denn
void foo(int& ref_in_foo); int main() { int i = 42; foo(i); }
Dieses Beispiel hatte mir wieder zu denken gegeben. Ursprünglich hatte ich es auch so verstanden, dass dies funktioniert, als ich ein paar Beispiel dazu gesehen hatte.
Als ich allerdings wieder über Funktionen nachgelesen hatte, war ich mir nicht mehr so sicher ob das funktioniert.Denn der Prototyp einer Funktion sagt doch auch, was die Funktion zurückgibt und was als Eingabe erwartet wird.
Dies führt dann kurioser Weise schon zu erster Irritation, denn:
#include <iostream> using namespace std; void foo(int i) { cout << "Input is : " << i << endl; } int main() { double j = 10; foo(j); // <-- funktioniert!! return 0; }
Also obwohl ich als Eingabe einen Integer deklariere, übernimmt die Funktion auch ohne Probleme eine double Variable. Okay, soweit ich das verstanden habe findet 'im Hintergrund' dann eine Typumwandlung statt (nennt man das so?).
Das sehe ich sehr schnell, wenn ich das ganze ändere zu:#include <iostream> using namespace std; void foo(int i) { cout << "Input is : " << i << endl; } int main() { double j = 10.25; foo(j); // <-- funktioniert!! return 0; }
Dann ist die Ausgabe einfach:
Input is : 10
Wurde in einen Integer verwandelt.
Also halten wir als Zwischenergebnis fest:
Ich kann auch andere Datentypen als im Funktionsprototype erwartet an eine Funktion übergeben, dann findet eine Typumwandlung statt.Mit der Referenz verhält es sich scheinbar wieder anders, weil eine Referenz selbst kein Datentyp ist? Sondern eben eine Referenz auf diesen? Klingt komisch, scheint aber so zu sein?
Also wenn ich nun deklariere:void bar(int & r_i) { cout << "Input is : " << r_i << endl; }
Dann bedeutet dies: "Initialisiere mir eine Integer-Referenz auf das was du als Eingabe bekommst."
Wieder kurioser Weise ist der Datentyp jetzt zwingend!! Folgendes funktioniert jetzt nicht mehr:
#include <iostream> using namespace std; void bar(int & r_i) { cout << "Input is : " << r_i << endl; } int main() { double j = 10.25; bar(j); // <--- funktioniert nicht!! return 0; }
Warum? Das kann ich nur wieder raten. Ich nehme an dass jetzt der Datentyp zwingend ist auf den die Referenz zeigt.
Also ich kann bei der Variablenübergabe an Funktionen durchaus eine Typumwandlung erwarten, aber keine Referenzumwandlung.Gruß,
Klaus.P.S.:
Ich habe es unbewusst auch schon übernommen, aber: Warum werden Beispielfunktionen oder Variablen immer als foo und bar bezeichnet?
-
foo und bar ... Gegenfrage: wieso stellen Leute immer Fragen deren Antworten sie sich ganz einfach selbst ergoogeln könnten?
Klaus82 schrieb:
Warum? Das kann ich nur wieder raten. Ich nehme an dass jetzt der Datentyp zwingend ist auf den die Referenz zeigt.
Weil non-const Lvalue-Referenzen nicht an Rvalues gebunden werden dürfen, und das Ergebnis einer Konvertierung eine Rvalue ist.
Also ich kann bei der Variablenübergabe an Funktionen durchaus eine Typumwandlung erwarten, aber keine Referenzumwandlung.
Was soll Referenzumwandlung bedeuten?
Wenn dann würde der Wert in den passenden Typ konvertiert, und die Referenz dann an die so entstandene Rvalue gebunden.Das ist in bestimmten Fällen auch erlaubt, nämlich wenn es eine Lvalue-Referenz auf const ist, oder eine Rvalue-Referenz.
Versuch z.B. einfach malvoid bar(int const & r_i) ...
-
314159265358979 schrieb:
1. Iterator auf das letzte Element holen.
2. Wenn ein Element gelöscht werden soll, Element mit *last tauschen.
3. Last erniedrigen
4. Remove & Erase IdiomSuper Idee. Wobei remove hier dann ja überflüssig ist. Statt swap mag auch einfach ein move-assignment reichen.
Also...
unsigned numelecs = electrons.size(); for (unsigned idx=0; idx<numelecs; /* kein ++idx hier*/) { ... if (muss electrons[idx] gelöscht werden?) { --numelecs; if (idx!=numelecs) { // falls idx nicht schon das letzte gültige war ... electrons[idx] = std::move(electrons[numelecs]); } // kein ++idx, weil an idx-ter Stelle ja // jetzt ein neues Electron steht, was wir nicht // ueberspringen wollen, oder wir schon am Ende sind } else { ++idx; // ok, weiter zum nächsten } } electrons.erase(electrons.begin()+numelecs,electrons.end());
(ungetestet)
Klaus82 schrieb:
[...]
Dies führt dann kurioser Weise schon zu erster Irritation, denn:#include <iostream> using namespace std; void foo(int i) { cout << "Input is : " << i << endl; } int main() { double j = 10; foo(j); // <-- funktioniert!! return 0; }
Wie gesagt, die Art der Parameterinitialisierung ist äquivalent zu
double j = 10; int i = j; // OK: implizite Konvertierung des double-Wertes nach int int& r = j; // Compile-Error: Auf was soll sich r denn beziehen? // Dass das hier nicht klappt ist ein Feature, denn // sonst würde das ganz schnell zu Bugs führen, weil // Du ggf beim Schreibzugriff über r Änderungen von j // erwarten würdest, was gar nicht sein kann. const int& c = j; // Das ist erlaubt. Hier bezieht sich die Referenz // auf ein temporär erzeugtes int-Objekt. Da du das // wegen const nicht verändern darfst, kannst du auch // nicht in die Falle von oben reinlaufen.
Die Sache hat mit Funktionen also gar nichts zu tun.
Klaus82 schrieb:
[...]
Warum? Das kann ich nur wieder raten.
[...] aber keine Referenzumwandlung.Zumindest nicht bei nicht-const Referenzen. Sei froh, dass das so ist!