PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Iterator als Eigenschaft, ok?



`kk
25-10-2005, 17:11
Hallo Forum.
Ich habe ein Problem.

Erstmal kurz zur Vorgeschichte:
Ich mache ein Programm zur Verwaltung von Decks fuer ein Kartenspiel.
Jede Karte hat einen Typ, z.B. "Human Wizard", "Lobotemist", usw.

Ich will den String nicht direkt als Eigenschaft mit in die "Card"-Klasse tun.
Deswegen habe ich jetzt zwei Klassen, "Card" und "CardTypeList",
in der sich jeder Kartentyp des Spiels einmal in einer Liste befindet.

Ich habe mir ueberlegt in der "CardTypeList"-Klasse ein Set zu
implementieren, zu der ich dann Kartentypen hinzufuegen kann und in der
"Card"-Klasse ist dann ein Iterator als Eigenschaft fuer den Typ der Karte,
der dann auf den entsprechen Typ in der Typ-Liste zeigt.

Macht man das so?
Wenn nein, wie macht mans sonst? ;)

Danke & Gruß
Kai

peschmae
25-10-2005, 17:33
Das Problem mit Iteratoren ist halt dass (zumindest bei den STL-Iteratoren) wann immer du an der Liste wo du den Iterator her hast was änderst, der Iterator nicht mehr gültig ist.
D.h. das Ding ist für deine Zwecke soweit ich das verstanden habe nicht wirklich brauchbar.

Was genau ist der Grund wieso du den String nicht als Member in dem Objekt speicherst?

MfG Peschmä

`kk
25-10-2005, 17:58
Hi peschmae, danke fuer deine Antwort. :)

Hm.. ich wuerde den Iterator const machen,
dann duerfte es das angesprochene Problem nicht geben.

Ich hab zwei Gruende warum ich keinen std::string nehmen moechte:
1) Es sind ueber 12.000 Karten, d.h. 12.000 mal einen langen String in jedem Karten-Objekt
2) Datenredundanz
3) Ich finde es unuebersichtlich

Hat jemand denn nochn anderen Vorschlag?
Ich muss ja keinen Iterator nehmen, mir faellt nur
momentan nichts Anderes ein...

Gruß
Kai

anda_skoa
25-10-2005, 18:23
Das hört sich nach einem Fall für einen shared pointer an, zum Beispiel shared_ptr<> aus der Boost lib.

Oder ein selbst implementiertes Handle

Ciao,
_

locus vivendi
25-10-2005, 18:34
Hm.. ich wuerde den Iterator const machen,
dann duerfte es das angesprochene Problem nicht geben.
Ob der Iterator "const" ist, hat nichts damit zu tun, ob er gültig ist. Bei welchen Operationen auf dem entsprechenden Container er gültig bleicht, liest du am besten in einer Referenz nach.

Wenn du einen Iterator zum Zeigen auf das Element im Container wegen dieser Problematik nicht gut verwenden kannst, dann könnte vielleicht ein Index in den Container an Stelle eines Iterators gehen. Z.b. ein Integer als Index in einen std::vector. Oder du verwendest eine Map.

`kk
25-10-2005, 21:00
Hi locus.
Das ist lustig..., denn genau so habe ich es schon probiert. ;)
Dann war der erste Gedanke wie immer der Richtige...

Edit:
So... nach mehr oder weniger kleinen Schwierigkeiten funktioniert es nun wunderbar:


std::pair< int, bool >
CardTypeList::add( const std::string& type )
{
if ( m_typelist.insert( std::make_pair( type, m_typelist.size() ) ).second )
return std::make_pair( m_typelist.size()-1, true );

m_iter = m_typelist.find( type );
return std::make_pair( (*m_iter).second, false );
}
Danke fuer den Schubser. :)

Gruß
Kai

`kk
26-10-2005, 16:24
So.. ich nochmal.
Die Methode da oben funktioniert natuerlich hervorragend..
nur komm ich jetzt nicht mehr ueber den Index an den Typ, den ich brauche.
Dafuer muesste es "int, string" heißen... zum Suchen brauche ich aber "string, int".

Ist irgendwie ne Zwickmuehle...
Kennt da jemand den Ausweg? :)

Ich brauechte irgendein Container mit zwei Schluesseln. :/

Danke & Gruß
Kai

locus vivendi
26-10-2005, 16:38
Irgendwie ist mir der Sinn deines Codeschnippsels auch nicht so klar. "m_typelist" ist eine Map, oder? Aber warum fügst du da Elemente ein, welche die Größe der Map enthalten? Ich dachte eigentlich, dass es gehen müsste, wenn du in deiner Karten-Klasse einen Index bzw. Schlüssel speicherst, und damit dann aus einer Map den entsprechenden Kartentyp herausholst (der, wenn ich dich richtig verstanden habe, als String gespeichert wird).


Ich brauechte irgendein Container mit zwei Schluesseln.
Boost hat einen solchen. Heißt "Multi Index Container".

`kk
26-10-2005, 16:43
Irgendwie ist mir der Sinn deines Codeschnippsels auch nicht so klar. "m_typelist" ist eine Map, oder?

Ja...
Ich habe ne Map genommen, weil ich nicht weiß
wie ich bei der Benutzung eines Vectors nach dem
Suchen durch den Iterator auf den Index komme.

Ich drueck mich manchmal etwas kompliziert aus,
hier lieber etwas Quellcode:



...
std::vector< std::string > vec;
std::vector< std::string >::iterator iter;

vec.push_back( "typ1" );
vec.push_back( "typ2" );
vec.push_back( "typ3" );

iter = find( vec.begin(), vec.end(), "typ2" );

/*
Hier muesste ich jetzt die aktuelle Position im Vector
zurueckgeben. Aber wie komme ich vom Iterator
auf den Index?

Ich koennte ganz simpel die Liste durchlaufen,
dann haette ich den Index. Aber ich dachte das geht
evtl. etwas eleganter (und vor allem schneller...):
*/

for (int i = 0; i < vec.size(); ++i) {
if ( vec[i] == type ) // Der typ, der eingefuegt werden soll
return i;

vec.push_back( type );
return vec.size();
}

return 0;
...


Danke fuer Hilfe.

Gruß
Kai

locus vivendi
26-10-2005, 17:19
Ja. Map statt vector, weil ich nicht weiß wie ich ueber den
Iterator die aktuelle Position im Vector zurueckgeben kann.
Das geht (z. B.) mit std::distance (also z.B. "distance(der_vector.begin(), anderer_iterator)")

Vermutlich verstehe ich da wieder irgend etwas falsch, aber mir ist nicht so ganz klar, weshalb du zusätzlich zum Schlüssel der Map noch einen Index brauchst. Die Map hatte ich ja gerade deshalb vorgeschlagen, weil man damit *anstelle* eines (numerischen) Indexes einen (fast) beliebigen Typ als Schlüssel benutzen kann. Ein Schlüssel ist ja nichts anderes als ein verallgemeinerter Index.

`kk
26-10-2005, 17:29
Na eben deshalb, weil ich nicht wusste wie ich
ueber den Iterator an den Index komme!
Also dachte ich mir, ich erstelle einfach ne Map mit dem String +
dem Index damit ich die Position zurueckgeben kann. :D

Aber dank deinem Tipp kann ich das jetzt nochmal
ausprobieren. Mit std::find gehts bestimmt viel schneller
als immer den ganzen Vector zu durchlaufen. :)

Danke auf jeden Fall schonmal..
Ich meld mich. ;)

Gruß
Kai

Edit: Hi nochmal..., bist du dir sicher das es distance heißt? Ich finde das weder in irgendeinem Buch noch ueber google.

Joghurt
26-10-2005, 17:56
Das Problem mit Iteratoren ist halt dass (zumindest bei den STL-Iteratoren) wann immer du an der Liste wo du den Iterator her hast was änderst, der Iterator nicht mehr gültig ist.Das stimmt so nicht! Es hängt immer von dem Container ab. Beispiel list:
Lists have the important property that insertion and splicing do not invalidate iterators to list elements, and that even removal invalidates only the iterators that point to the elements that are removed.

locus vivendi
26-10-2005, 18:03
Na eben deshalb, weil ich nicht wusste wie ich
ueber den Iterator an den Index komme!
Also dachte ich mir, ich erstelle einfach ne Map mit dem String +
dem Index damit ich die Position zurueckgeben kann
Okay, jetzt habe ich es verstanden.


Edit: Hi nochmal..., bist du dir sicher das es distance heißt? Ich finde das weder in irgendeinem Buch noch ueber google.
Ja. std::distance aus dem Header <iterator>. Das müsste in jeder guten Referenz zu finden sein. Z.b. in der von Dinkumware. Aber bei einem Vector musst du auch nicht distance nehmen. Dessen Iteratoren unterstützen eine "-"-Operation, die ebenfalls den Abstand zwischen zwei Iteratoren berechnet.

`kk
26-10-2005, 19:53
Hi locus.
Dank dir, es funktioniert nun super...
genau so wollte ich das haben. :)

Fuer alle, die interessiert sind wie es nun aussieht:


std::pair< int, bool >
CardTypeList::add( const std::string& type )
{
std::vector< std::string >::iterator found;
found = find( m_typelist.begin(), m_typelist.end(), type );

if ( found != m_typelist.end() ) {
int index = m_typelist.begin() - found;
return std::make_pair( index, false );
}

m_typelist.push_back( type );
return std::make_pair( m_typelist.size(), true );
}

Gruß
Kai

locus vivendi
26-10-2005, 20:02
Vorsicht!

int index = m_typelist.begin() - found;
Das ist zwar erlaubt, aber du musst dir im klaren darüber sein, dass "index" nun nicht positiv ist.

`kk
26-10-2005, 20:22
Wie soll ichs besser machen?

locus vivendi
26-10-2005, 20:36
Das ist ausnahmsweise so wie in der Mathematik: Wenn a - b positiv ist, dann ist b - a negativ, und umgekehrt.

`kk
26-10-2005, 20:57
Hab grad' keine passende Ausrede... danke. ;)