[STL] Vector iterator an Position springen



  • Hi,
    wahrscheinlich wieder eine recht triviale Frage.

    Ich würde gerne an eine zufällig bestimmte Stelle in meinem Vector springen, z.B. einleitend so:

    vector<double> numbers;
    int size = numbers.size();
    int position = rand() * size;
    

    Jetzt habe ich gesehen, dass ich mit den beiden Optionen at und operator[] an eine Stelle springen kann und mir das dortige Element anzeigen lassen kann.
    Zumindest in der C++ Referece:

    Return Value
    The element at the specified position in the vector.

    Ich will ja aber nicht das Element selbst, sondern die Adresse für den Iterator, dass ich anschließend das Element bearbeiten kann. Ich will das Element nicht nur angezeigt kriegen, sondern es modifizieren.

    Ich hätte also etwas derartiges erwartet:

    vector<double>::iterator = numbers.at(position);
    

    Stehe ich da gerade auf dem Schlauch? Das muss doch in diese Richtung möglich sein? 😕

    Gruß,
    Klaus.



  • std::vector<double>::iterator iter = numbers.begin() + position;
    


  • Hä?

    std::vector<double> v;
    v.push_back(33);
    v.push_back(42);
    v.push_back(77);
    
    v[std::rand() % v.size()] = 99;
    

  • Mod

    Nimm begin() + position, wenn du den Iterator zur Position möchtest. Deine Beschreibung klingt aber so, als fehlten dir die Grundlagen vom vector. at() und operator[] geben eine Referenz auf das Element zurück, das kannst du darüber bearbeiten:

    vector<int> foo(5);
    foo[3] = 2;
    

    Wäre auch reichlich unkomfortabel, wenn das nicht so einfach ginge.



  • Warum willst du den Iterator, wenn du auch über den Index auf das Element zugreifen kannst? Egal..

    vector<double> numbers;
    
    size_t pos = rand() * numbers.size();
    
    double val = numbers[pos];
    
    vector<double>::iterator it = numbers.begin() + pos;
    

    Edit:
    Sach ma Sepp, hast du´n Trigger auf das Forum? Ich hab den Eindruck, du schreibst Antworten 4.3ns nachdem ein Benutzer einen Beitrag geschrieben hat.



  • Was mir grad noch auffällt:

    Klaus82 schrieb:

    int position = rand() * size;
    

    Ich nehme an, du meinst

    int position = rand() % size;
    


  • DocShoe schrieb:

    Sach ma Sepp, hast du´n Trigger auf das Forum? Ich hab den Eindruck, du schreibst Antworten 4.3ns nachdem ein Benutzer einen Beitrag geschrieben hat.

    😕 Du lässt nicht deinen Bot antworten und schreibst den ganzen Quatsch selbst?


  • Mod

    DocShoe schrieb:

    Edit:
    Sach ma Sepp, hast du´n Trigger auf das Forum? Ich hab den Eindruck, du schreibst Antworten 4.3ns nachdem ein Benutzer einen Beitrag geschrieben hat.

    In letzter Zeit sind aber immer seldon und cooky451 vor mir. Ich war auch schon einmal besser 😞



  • SeppJ schrieb:

    DocShoe schrieb:

    Edit:
    Sach ma Sepp, hast du´n Trigger auf das Forum? Ich hab den Eindruck, du schreibst Antworten 4.3ns nachdem ein Benutzer einen Beitrag geschrieben hat.

    In letzter Zeit sind aber immer seldon und cooky451 vor mir. Ich war auch schon einmal besser

    Müsst ihr nicht arbeiten oder seid ihr in Rente? 😃





  • Ah,
    danke für die Antworten. Tatsächlich kann ich auf Elemente des Vektors wie bei einem Array über den Index zugreifen.

    Ich habe dazu mal was gebastelt:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class FOO
    {
    public:
    	FOO(int i){ fooVariable = i; }
    	double fooVariable;
    
    };
    
    int main()
    {
    	vector<FOO> v_foo;
    
    	for(int i = 0; i < 20; ++i)
    	{
    		v_foo.push_back(FOO(i));
    	}
    
    	for(unsigned int i = 0; i < v_foo.size(); ++i)
    	{
    			cout << v_foo[i].fooVariable << endl;
    	}
    
    	return 0;
    
    }
    

    Jetzt habe ich aber das Problem, dass ich gerne etwas aus dem Vektor an einer bestimmten Stelle löschen würde. Der Knackpunkt ist nur, dass die Operation erase() als Input eine Iteratorposition haben möchte, z.B. kann meine zweite For-Schleife so aussehen:

    for(unsigned int i = 0; i < v_foo.size(); ++i)
    	{
    		if(v_foo[i].fooVariable == 10)
    		{ v_foo.erase(iter); }
    
    			cout << v_foo[i].fooVariable << endl;
    	}
    

    Nur wie kriege ich jetzt die Position eines Iterators iter (siehe Code Schnippsel) an die Stelle mit dem Index i ?
    Muss ich da die ganze Zeit einen Iterator mitlaufen lassen?

    vector<FOO>::iterator iter = v_foo.begin();	
    	for(unsigned int i = 0; i < v_foo.size(); ++i)
    	{
    		if(v_foo[i].fooVariable == 10)
    		{ v_foo.erase(iter); }
    
    			cout << v_foo[i].fooVariable << endl;
    		iter++;
    	}
    

    Das funktioniert zwar, wäre doch aber ziemlich umständlich, wenn ich schon Zugriff über einen Index habe. 😕

    Gruß,
    Klaus.

    P.S.: Ich bemerke gerade: Die cpp-Umgebung wertet "[i]" als Beginn der Italic Umgebung, die code-Umgebung tut das zum Glück nicht.


  • Mod

    Dir wurde doch schon bestimmt 5x gesagt, wie du zu einem Index den Iterator bekommst. Lies nochmal alle Antworten gründlich.

    Außerdem möchtest du deine ganze Löschschleife vermutlich eher durch ein erase-remove ersetzen:
    http://en.wikipedia.org/wiki/Erase-remove_idiom

    P.S.: Ich weiß nicht, was du für Probleme mit den Tags hast:

    foo[i]; bla
    

    P.P.S.: Hah, jetzt sehe ich, was du meinst. Aber ich kann es nicht reproduzieren, du hast da irgendwas ganz geheimnisvolles in deinem Beitrag angestellt. ICh werde dem bei Gelegenheit mal nachspüren.



  • SeppJ schrieb:

    Dir wurde doch schon bestimmt 5x gesagt, wie du zu einem Index den Iterator bekommst. Lies nochmal alle Antworten gründlich.

    Na ja, wiederholt lese ich das:

    seldon schrieb:

    std::vector<double>::iterator iter = numbers.begin() + position;
    

    Also kann ich z.B. eingeben:

    iter = v_foo.begin() + 13;
    

    Und dabei springt der Iterator jetzt an diese Stelle? Wenn das ganze nur bedeutet, dass intern 13 mal iter++ aufgerufen wird, dann wäre das ja Quatsch.

    SeppJ schrieb:

    Außerdem möchtest du deine ganze Löschschleife vermutlich eher durch ein erase-remove ersetzen:
    http://en.wikipedia.org/wiki/Erase-remove_idiom

    Ich gucks mir an.

    Gruß,
    Klaus.


  • Mod

    Wie kommst du denn auf die Idee? vector-Iteratoren sind random_access-Iteratoren, mit denen kann man rechnen. Wäre sonst doch total bescheuert. Die Standardbibliothek ist schon recht gut durchdacht 🙂 . (Natürlich nicht perfekt)

    Wenn du es eine runde abstrakter möchtest, kannst du auch std::advance benutzen, dann geht das auch mit nicht-random-access-Iteratoren. Wobei bei einem list-Operator dann natürlich 13x operator++ aufgerufen würde, da es anders nicht geht. Aber dank Templatemagie würde für den vector-Iterator ein normales +13 gemacht.



  • seldon schrieb:

    Was mir grad noch auffällt:

    Klaus82 schrieb:

    int position = rand() * size;
    

    Ich nehme an, du meinst

    int position = rand() % size;
    

    Nein. Ich habe einen Zufallsgenerator, der Zufallszahlen zwischen 0 und 1 generiert. D.h. wenn ich ein zufällig bestimmtes Element des Vektors haben möchte, so mache ich:

    unsigned int size = r_electrons.size();
    	unsigned int position = (*p_random)() * size;
    
    	r_electrons[position].energy = r_electrons[position].energy + transfered_energy;
    

    Allerdings bekomme ich da nach ein paar Durchläufen einen Speicherzugriffsfehler.

    Also scheint es nicht so richtig zu klappen. Habe ich dabei einen Gedankenfehler was schief gehen könnte?

    Gruß,
    Klaus.


  • Mod

    Da kann ja auch size als position rauskommen, das wäre dann jenseits der Grenze.

    Was du aber bisher so gezeigt hast, flößt nicht gerade Zuversicht ein, dass der Rest des Programmes richtig wäre, wahrscheinlich hast du noch mehr Fehler.



  • SeppJ schrieb:

    Da kann ja auch size als position rauskommen, das wäre dann jenseits der Grenze.

    Das stimmt natürlich, dann muss ich das korrigieren:

    unsigned int position = (*p_random)() * (size - 1);
    

    SeppJ schrieb:

    Was du aber bisher so gezeigt hast, flößt nicht gerade Zuversicht ein, dass der Rest des Programmes richtig wäre, wahrscheinlich hast du noch mehr Fehler.

    Ja,
    irgendwo knirscht es da ganz gewaltig.

    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
    }
    

    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. 😉 😞

    Gruß,
    Klaus.


  • Mod

    Solche Abstürze kann man am besten im Debugger oder mit Tools wie valgrind nachvollziehen, dazu bräuchten wir aber den gesamten Code (möglichst weit gekürzt, so dass deine Fehler gerade noch auftreten). Oder das kannst du natürlich auch selber machen, muss man sowieso irgendwann mal üben.

    Vermutlich liegen deine Fehler ganz woanders. Dadurch, dass du deine Klassen nicht sauber designed hast, du selber manuelle Speicherverwaltung probiert hast (ohne es zu können) oder du irgendwo C-Mittel mit C++ gemischt hast (ohne die Fallstricke genau zu kennen).



  • SeppJ schrieb:

    Oder das kannst du natürlich auch selber machen, muss man sowieso irgendwann mal üben.

    Ja, ich versuche mich gerade an gdb...

    SeppJ schrieb:

    Vermutlich liegen deine Fehler ganz woanders. [..]

    Wahrscheinlich. Und nur durch das Aufrufen der Klassenfunktion kommt der Fehler ans Licht, sonst habe ich scheinbar Glück, dass nichts passiert.

    Gruß,
    Klaus.



  • 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.


Anmelden zum Antworten