Iterator nicht korrekt

little-smile

Grünschnabel
Hallo Ihr Lieben,

Mein Problem ist folgendes. Ich habe eine Sequenz (gepeichert in einem STL Vektor). Jede Position entspricht einen Eintrag. Ich will nun meine Sequenz in gleich lange Teilstücke teilen (Grams) . Die Start/End - Infos werden dann in pro Gram in GramInfo gespeichern. Dies Grams werden dann wieder in einem Vector von GramInfo, hier GramTable gespeichert! So weit, so gut!

Code:
class GramInfo
{
	public:
		/*Constructor and Destructor*/
		GramInfo();
		GramInfo( const unsigned int& hash, const pair<vector<int>::const_iterator,vector<int>::const_iterator>& pos);
		virtual ~GramInfo();	
	
		/*further member functions*/
		void setGramStart(const pair<vector<int>::const_iterator,vector<int>::const_iterator>& pos){GramPos = pos;}
		void setHashValue(const unsigned int& hash){GramHashValue = hash;}
		
		pair<vector<int>::const_iterator,vector<int>::const_iterator>& getGramPos(){cout << *GramPos.first << endl ; return GramPos;}
		const unsigned int& getGramHashValue()const{return GramHashValue;}
		

	public:
		unsigned int GramHashValue;
		pair<vector<int>::const_iterator,vector<int>::const_iterator> GramPos;
	
};


class GramTable: public vector<GramInfo>
{
	public:
		GramTable(){}
	  	virtual ~GramTable(){}

  		void addGram(const unsigned int& hash, const pair<vector<int>::const_iterator,vector<int>::const_iterator>& pos) 
  		{ 
  			push_back( GramInfo(hash, pos ) ); 
  		} 
};

Mein Problem ist nun, wenn ich mir in der Main meine Werte ausgeben lasse, erhalte ich für das erste Gram, genauer für dessen Start-Position einen falschen Wert. Er zeigt folglich auf ein falschen Start. Die Endposition, sowie der errechnete hash sind aber korrekt. Auch für alle folgenden Grams sind die Werte korrekt!
Auch wenn ich den Wert abfrage, bevor ich das insert in addGram mache, bzw. mir den Wert im Kosntruktor für GramInfo ausgeben lasse. Immer ist der Wert korrekt. Nur wenn ich ihn mir dann in der Main ausgeben lasse, komm Müll!

Code:
GramTable gramTab;
GramTable::iterator gram_it;

for (gram_it = gramTab.begin();	gram_it != gramTab.end(); gram_it++){
    
   pair<vector<int>::const_iterator,vector<int>::const_iterator> pos= (*gram_it).getGramPos();

   cout <<" => "<< (*gram_it).getGramHashValue()<< "\t" << *pos.first<< "\t" << *pos.second <<endl ;
				
}

Auch wenn ich folgendes mache, erhalte ich für das erste Gram nur Müll.
Alle folgenden liefern aber immer die korrekten Werte.

Code:
for(vector<int>::const_iterator g = pos.first; g <= pos.second; g++)
{
	cout << *g;	
}

Ich hoffe, es kann mir jemand helfen, weil ich weiß leider nicht mehr weiter.

Thx little-smile
 
Ich such's gerade ... generell sollte man von Std. Klassen nicht ableiten ... ist immer die Frage ob sie überhaupt dafür geeignet sind (virtual d-tor etc.) ... find aber immer nur die andeutungen von anderen ... müsste man im Std. nachgucken ob der d-tor von std::vector dafür geeignet wäre ...

Bearbeitung
So hab's in Effektiv C++ gefunden ... Tipp 7 zu virtuellen Destruktoren in Basisklassen. Weder die std-string-Klasse noch ein Std. Container-Type (vector, list, set, tr1::unordered_map, usw.) hat einen virtuellen Destruktor. Das Verhalten is nicht wirklich definiert was dann passiert ...
 
Zuletzt bearbeitet:
Hi.
So hab's in Effektiv C++ gefunden ... Tipp 7 zu virtuellen Destruktoren in Basisklassen. Weder die std-string-Klasse noch ein Std. Container-Type (vector, list, set, tr1::unordered_map, usw.) hat einen virtuellen Destruktor. Das Verhalten is nicht wirklich definiert was dann passiert ...
Um das nochmal etwas zu erläutern: damit ist gemeint, das der C++ Standard ausdrücklich undefiniertes Verhalten erlaubt, falls versucht wird ein Objekt einer abgeleiteten Klasse durch einen Zeiger auf die Basisklasse (welche keinen virtuellen Destruktor definiert) zu löschen.

D.h. man kann generell diese von STL Containern abgeleiteten Objekte nicht sicher durch Zeiger oder Referenzen benutzen.

In deinem (@little-smile) Fall dürfte nichts passieren, da - ausgehend von deinem Codeausschnitt - solche Situationen nicht vorkommen.

Zum Problem mit dem Iterator: kann es sein, dass du den Container noch veränderst und dadurch der Iterator ungültig wird? Wie sieht denn der Algorithmus zum Teilen und Einfügen aus?

Gruß
 
Hi deepthroat,

Dann poste ich dir mal meinen Code, ist nicht so kurz und prägnant, wie du es wohl gewohnt bist. Ich hoffe, du kommst trotzdem durch:

Code:
void Sequences::extractGram(pair<vector<int>::const_iterator, vector<int>::const_iterator>& gram, const vector<int>::const_iterator start, const int& gram_length)
{	
	vector<int>::const_iterator end = start;
	advance(end,gram_length-1);
			
	gram = make_pair(start, end);
}

und

Code:
void Sequences::hash(GramTable* gram_table, const int& gram_length, const int& step_width)
{
	vector<int> seq_encoded = getSequenceEncoded();
	vector<int>::const_iterator seq_end, gram_start;
	pair<vector<int>::const_iterator,vector<int>::const_iterator> gram;
	int hash_value;
	
	gram_start = getSequenceEncodedStart();
	seq_end = getSequenceEncodedEnd();
	
	/*extract the grams, while proceeding step width is possible */
	while( gram_length <= (int)(seq_end - gram_start))
	{
		/*store start and end position for the actual gram in an pair<start,end> gram*/
		extractGram(gram, gram_start, gram_length);
		
		/*compute the hash value for the actual gram, returns "-1" when an invalid nucleotid is within the gram*/
		hash_value = computeHashValue(gram);
		
		/*add the gram infos into the GramTable of the sequence*/
		if(hash_value != -1)
		{
			//cout << "=>"<< hash_value  <<"\t start: "<< *gram.first << "end:" << *gram.second <<endl; 	
		
			(*gram_table).addGram(hash_value, gram);			
		}

		/*shift the window further to compute the next gram*/
		shiftSequence(step_width, gram_start);
	}
	
	/*remained sequence is shorter than the gram_length, we has to execute a backshift*/
	if(gram_length > (int)(seq_end - gram_start)){
	
		int diff = gram_length - (int)(seq_end - gram_start);
		backshiftSequence(diff, gram_start);
	
		/*store start and end position for the actual gram in an pair<start,end> gram*/
		extractGram(gram, gram_start, gram_length);

		/*compute the hash value for the actual gram, returns "-1" when an invalid nucleotid is within the gram*/
		hash_value = computeHashValue(gram);
		
		/*add the gram infos into the GramTable of the sequence*/
		if(hash_value != -1)
		{
			(*gram_table).addGram(hash_value, gram);
		}
	}
	return;
}


Ich hätte da überhaupt mal eine allgemeine Frage, ich kann einen Iterator schon an eine Funktion übergeben. Oben funktioniert es ja theoretisch. Nun wollte ich ähnliches für eine Object der Klasse GramTable machen, da bekomme ich aber eine Fehlermeldung in meiner Headerdatei, dass der Const:iterator nicht deklariert ist. Was mich verdutzt! Kannst du vllt dazu auch was sagen!
(Wie man an meinen Betrag sieht, bin ich ziemlich neu was das ganze angeht! Sorry, dass ich euch so quäle!)

Thx, little-smile
 
kleiner Zusatz:

Ich habe mal statt nur einer Sequenz mal mehrere durchlaufen lassen. Dabei viel mir auf, dass dieses Phänomen nicht bei allen auftritt. Darüberhinaus gibt es dann auch ein Paar, bei denen der letzte Wert (Ende vom letzten Gram) auch wo anders hinzeigt!

Diese Beobachtung, macht es noch verwirrender, somal ich ja nix an den Einträgen in GramTable mache, als sie einlesen und auszugeben!

Gruß, little-smile
 
Hi.

Ich kann in deinem Codeausschnitt kein Problem entdecken.

Allerdings etwas merkwürdig ist, wie du die Iteratoren speicherst. Der Enditerator zeigt ja eigentlich immer hinter das letzte Element und nicht auf das letzte Element.

Warum erzeugst du denn eine Kopie von der encodedSequence, wenn du die Variable gar nicht verwendest? Was genau machen denn eigentlich die Funktionen getSequenceEncodedStart und getSequenceEncodedEnd? Dabei wird aber nicht irgendwie eine Kopie der Sequenz erzeugt oder?

Und shiftSequence(k, i) macht doch sicher das gleiche wie std::advance(i, k), oder?! Findest du diese "Umbenennung" wirklich sinnvoll bzw. notwendig? Bei std::advance weiß jeder sofort was passiert, bei deiner Funktion müßte man erstmal nachschauen...

Zu dem Problem mit dem Iterator kann ich nicht viel sagen. Dazu müßtest du mal den relevanten Code zeigen.

Wenn ich jetzt mal davon ausgehe das alles korrekt in der GramTable gespeichert ist, müßte der Fehler ja eigentlich bei der Ausgabe liegen.

Ansonsten wäre ein Minimal-Demoprogramm ganz nützlich um mal zu sehen was richtig bzw. was falsch in dem Zusammenhang überhaupt bedeutet. Die Hashwertberechnung funktioniert aber einwandfrei, oder?!

Gruß
 
Zurück