[ERLEDIGT] Zeiger auf Map



  • darkfate schrieb:

    Ist es überhaupt nötig mit Zeigern zu arbeiten?

    Nein.

    darkfate schrieb:

    Vielleicht gibt sich map beim Beenden ja selber frei?!

    Ja.

    C++ ist nicht das Gleiche wie Java...



  • Du brauchst keine Zeiger und es gibt std::greater<int> .



  • Und der Vollstängidkeit halber:

    Der syntaktisch richtige Aufruf wäre

    (*this->coordinates)[new_id] = new_utm;
    

    gewesen.



  • Und mit dem Implementieren von Standardkonstruktor und Destruktor, aber dem Vergessen von Kopierkonstruktor und Zuweisungsoperator eröffnest du dem undefinierten Verhalten ungeahnte Möglichkeiten. Stichwort Regel der Grossen Drei.

    Ausserdem, fürs nächste Mal (falls es um mehr als nur > geht):

    class Compare{
        public:
            bool operator()(const unsigned int &one, const unsigned int &two){
                if(one>two) return true;
                else return false;
            }
    };
    

    wird zu

    struct Compare {
        bool operator() (unsigned int lhs, unsigned int rhs) {
            return lhs > rhs;
        }
    };
    

    Die Konstruktor-Initialisierungsliste wäre auch eine Idee. Und statt jeweils class vor Klassentypen zu schreiben würde ich die Klasse einmal deklarieren und dann nur noch den Bezeichner verwenden.



  • Nexus schrieb:

    Und mit dem Implementieren von Standardkonstruktor und Destruktor, aber dem Vergessen von Kopierkonstruktor und Zuweisungsoperator eröffnest du dem undefinierten Verhalten ungeahnte Möglichkeiten.

    Gilt es auch wenn man nie zuweisen möchte? Kann man dafür irgend eine Sackgassenfunktion erstellen die beides verbietet?

    Nexus schrieb:

    Stichwort Die Konstruktor-Initialisierungsliste wäre auch eine Idee. Und statt jeweils class vor Klassentypen zu schreiben würde ich die Klasse einmal deklarieren und dann nur noch den Bezeichner verwenden.

    Danke für den Tipp, könntest du mir kurz zeigen wie dann der Code aussieht.



  • darkfate schrieb:

    Gilt es auch wenn man nie zuweisen möchte? Kann man dafür irgend eine Sackgassenfunktion erstellen die beides verbietet?

    Ja, einfach Kopierkonstruktor und Zuweisungsoperator beide privat deklarieren und nicht definieren.

    darkfate schrieb:

    Danke für den Tipp, könntest du mir kurz zeigen wie dann der Code aussieht.

    Statt

    MyClass::MyClass(int number)
    {
        member1 = number;
        member2 = "hallo";
    }
    

    hast du

    MyClass::MyClass(int number) : member1(number), member2("hallo")
    {
    }
    

    Und was das überflüssige class angeht: Am Anfang der Datei schreibst du (falls der Typ noch nicht definiert ist):

    class UTM;
    

    und bei der Verwendung

    void addcoordinate(unsigned int new_id, UTM new_utm);
    


  • Jetzt habe ich die Header Datei so verändert:

    #include "geotopology.h"
    
    GEOTopology::GEOTopology(){
    }
    
    GEOTopology::~GEOTopology(){
    }
    
    void GEOTopology::addcoordinate(unsigned int new_id, class UTM new_utm){
    	coordinates[new_id] = new_utm;
    }
    void removecoordinate(unsigned int new_id){
    
    }
    

    Nun sagt mir der Compiler das meine UTM Klasse keinen Default Konstruktor hat. Wahrscheinlich das, was in der Vornachricht gemeint war mit dem : initialisieren.

    Meine utm.h sieht so aus.

    struct _COORDINATE{
    	double h;
    	double v;
    	double d;
    	// mode=0 -> XYZ
    	// mode=1 -> HVD
    	bool mode;
    };
    
    typedef struct _COORDINATE COORDINATE; 
    
    class UTM{
    	private:
    		COORDINATE coo;
    
    	public:		
    		UTM(COORDINATE coo);
    ......
    

    Ich möchte keinen Default Konstruktor Aufruf, sondern das direkt beim Aufruf eine Koordinate übergeben wird. Wie ist das mit dem ":" initialisierer zu lösen?



  • Wird wohl ohne Zeiger nicht zu lösen sein..
    Mit zeigern könnte man beim ersten addcoordinate prüfen ob der *coordinate Zeiger NULL ist und einen neuen anlegen...

    Sehe sonst keine Bequeme Lösung.



  • darkfate schrieb:

    Jetzt habe ich die Header Datei so verändert:

    void GEOTopology::addcoordinate(unsigned int new_id, class UTM new_utm)
    

    Warum hier immer noch class ?

    darkfate schrieb:

    Nun sagt mir der Compiler das meine UTM Klasse keinen Default Konstruktor hat. Wahrscheinlich das, was in der Vornachricht gemeint war mit dem : initialisieren.

    Nein, der std::map::operator[] erfordert, dass ein Defaultkonstruktor für den Werttypen vorhanden ist. Ansonsten verwende die Memberfunktionen find() und insert() .

    darkfate schrieb:

    struct _COORDINATE{
    };
    
    typedef struct _COORDINATE COORDINATE;
    

    Warum? Wir sind nicht in C. Definiere direkt struct COORDINATE .

    darkfate schrieb:

    public:		
    		UTM(COORDINATE coo);
    

    Nimm statt Kopien lieber Referenzen auf Const, wenn es sich um grössere Objekte handelt.

    darkfate schrieb:

    Wird wohl ohne Zeiger nicht zu lösen sein..
    Mit zeigern könnte man beim ersten addcoordinate prüfen ob der *coordinate Zeiger NULL ist und einen neuen anlegen...

    Sehe sonst keine Bequeme Lösung.

    Doch. Überprüfe manuell, ob die Map das Element bereits speichert, und füge ansonsten eins ein (benutze oben genannte Memberfunktionen).



  • Nexus schrieb:

    Warum hier immer noch class ?

    Keine Ahnung? Ich habe es eigentlich dort reingeschrieben damit ich weiß dass es eine Klasse ist? Ist so etwas falsch?

    Nexus schrieb:

    NNein, der std::map::operator[] erfordert, dass ein Defaultkonstruktor für den Werttypen vorhanden ist. Ansonsten verwende die Memberfunktionen find() und insert() .

    Nexus schrieb:

    typedef struct _COORDINATE COORDINATE;
    

    Warum? Wir sind nicht in C. Definiere direkt struct COORDINATE

    Soweit ich weiß müsste man sonst immer struct COORDINATE schreiben. Ist es bei C++ nicht mehr der Fall? Vielleicht gilt es auch für die neuen C99 Standards nicht mehr...

    Nexus schrieb:

    [cpp]Nimm statt Kopien lieber Referenzen auf Const, wenn es sich um grössere Objekte handelt.

    Wenn ich dann von Außen die Koordinate zerstöre oder verändere, dann wird doch auch die Koordinate in der List zerstört oder verändert?

    Nexus schrieb:

    Doch. Überprüfe manuell, ob die Map das Element bereits speichert, und füge ansonsten eins ein (benutze oben genannte Memberfunktionen).

    Ich versuchs..

    Danke schonmal für den umfangreichen Support an alle.



  • darkfate schrieb:

    Soweit ich weiß müsste man sonst immer struct COORDINATE schreiben. Ist es bei C++ nicht mehr der Fall?

    Nein, und das gleiche gilt auch für class . Lass die Schlüsselwörter also bei der Variablendeklaration ruhig weg.

    darkfate schrieb:

    Wenn ich dann von Außen die Koordinate zerstöre oder verändere, dann wird doch auch die Koordinate in der List zerstört oder verändert?

    Ja, in der Liste dürfen auch Kopien stehen. Ich bezog mich auf die Parameterübergabe an den UTM -Konstruktor; diesen kannst du mit einer Const-Referenz als Parameter so deklarieren:

    UTM(const COORDINATE& coo);
    


  • Mit

    coordinates.insert()
    

    steht mir _Pairib insert(const value_type &_Val) zur verfügung. Wie soll da der Key und die Daten rein?



  • Schau mal auf www.cplusplus.com nach, dort gibt es auch Anwendungsbeispiele. Die Seite ist ein gutes Nachschlagewerk zur Standardbibliothek.



  • Nexus schrieb:

    Schau mal auf www.cplusplus.com nach, dort gibt es auch Anwendungsbeispiele. Die Seite ist ein gutes Nachschlagewerk zur Standardbibliothek.

    Danke für den Link... habs gefunden.

    Was ein wenig Konfus ist: Zeile 24,25
    http://www.cplusplus.com/reference/stl/map/insert/

    mymap.insert (it, pair<char,int>('b',300));  // max efficiency inserting
    mymap.insert (it, pair<char,int>('c',400));  // no max efficiency inserting
    

    Warum sollte das erste Verfahren effizient sein und das zweite nicht? da ändern sich doch nur die die Werte und nicht der Vorgang selbst?

    Gibt es eine Möglichkeite ohne Pair auszukommen? Dieses first, second ist ein wenig ungewöhnlich. Bei coordinate[id] = wert wie in http://www.cplusplus.com/reference/stl/map/insert/ ist es sehr bequem. Kann ich bei utm einfach einen leerden Default Konstruktor erstellen? Ist der Weg mit Pair der übliche? Wenn ja dann werde ich mich auch dran halten..



  • darkfate schrieb:

    Warum sollte das erste Verfahren effizient sein und das zweite nicht? da ändern sich doch nur die die Werte und nicht der Vorgang selbst?

    Wenn du die Überladung

    iterator insert ( iterator position, const value_type& x );
    

    nimmst, gibst du der Map einen Tipp, wo das Element einzufügen ist. Wenn der Tipp stimmt, entfällt daher die logarithmische Suche und du hast praktisch eine O(1)-Einfügung.

    Aber im Allgemeinen solltest du die einparametrige Überladung von insert() benutzen:

    pair<iterator,bool> insert ( const value_type& x );
    

    darkfate schrieb:

    Gibt es eine Möglichkeite ohne Pair auszukommen?

    Nein, aber du kannst mit std::make_pair() die Typangabe weglassen, was vor allem bei komplexeren Typen Vorteile hat:

    mymap.insert(pair<char,int>('b',300));
    

    wird zu

    mymap.insert(std::make_pair('b',300));
    

    Wenn dir das immer noch zu mühsam ist, kannst du dir ja eine Funktion schreiben:

    template <typename Key, typename Mapped>
    void map_insert(std::map<Key, Mapped>& map, const Key& key, const Mapped& mapped)
    {
        map.insert(std::make_pair(key, mapped));
    }
    

    So kannst du z.B. auch eine Exception werfen, wenn ein Objekt bereits vorkommt. Oder einfach den Rückgabewert von std::map::insert() weiterleiten. Der Aufruf sieht so aus:

    map_insert(mymap, 'b', 300);
    

    darkfate schrieb:

    Kann ich bei utm einfach einen leerden Default Konstruktor erstellen? Ist der Weg mit Pair der übliche? Wenn ja dann werde ich mich auch dran halten..

    Ich würde nicht nur aufgrund der Einfügungssyntax von std::map einen Defaultkonstruktor bereitstellen. Dieser ist dann auch in anderen Situationen verfügbar, wo er unangebracht ist. Zum Beispiel wenn du vergisst, ein Member einer Klasse zu initialisieren: Mit Defaultkonstruktor erfährst du nichts, aber die Membervariable hat möglicherweise einen sinnlosen Wert (Logikfehler zur Laufzeit). Ohne Defaultkonstruktor hingegen erfährst du zur Kompilierzeit von dem Fehler.



  • Super! Danke!


Anmelden zum Antworten