Datentyp mit decltype



  • Hallo zusammen -
    ich stehe im Moment vor einem (mir) interessantem Problem !

    Ich denke bevor ich mir einen abbreche und das Problem umschreibe
    sagt in diesem Fall Ein Quelltext mehr als tausend Worte:

    class StringTable
    {
    private:
    	typedef std::pair<QHash, const char*> tPair;
    typedef 
    unordered_map<tPair> /*Funktioniert nicht => zu wenig Argumente */
    unordered_map<declype(tPair.first),decltype (tPair.second)> /*Funktioniert nicht=> decltype erwartet Ausdruck */
    unordered_map<declype(tPair().first),decltype (tPair().second)> /*Funktioniert, löst allerdings 2 mal einen Konstruktor aus*/
    tMap;
    	tMap table;
    .
    .
    .
    

    Wie man sieht möchte ich mithilfe des typedef...tPair steuern wie die zugehörige Map erstellt wird um bei einer späteren Änderung des gespeicherten Pair nicht an 100 Stellen die Änderung nachpflegen zu müssen.

    Ich habe (während ich dieses Post geschrieben habe 🕶 ) eine Lösung gefunden die Funktioniert (s.o.) die ich allerdings für minder elegant halte!

    Warum gibt es eigentlich kein Map-template welches direkt ein Pair akzeptiert?

    Hat hier eventuell jemand eine schönere Lösung?

    Danke für die Aufmerksamkeit!



  • typedef unordered_map<tPair::first_type, tPair::second_type> tMap;
    

    😉

    Deine Lösung löst übrigend keinen Konstruktor aus. Der Ausdruck in einem decltype() wird nicht ausgewertet. Würde ja auch keinen Sinn machen, da das ja zur Compiletime passieren müsste...



  • Wow - das ging schnell; Danke! 🙂

    Sollte mir vielleicht doch mal ein STL-Buch zu gemüte führen...



  • Evtl. reicht dir auch das schon: http://www.cplusplus.com/reference/std/utility/pair/ 😉



  • Hallo nochmal!

    Ich habe für die gleiche Klasse direkt das nächste Problem,
    konkret geht es um das saubere aufräumen o.g. Struktur...

    Ist mir eigtl. etwas peinlich weil sowas ja standard ist aber ich komme mit meinem Latein hier nicht weiter!

    Ich schicke einfach mal den Code des destruktor mit der Anmerkung das nichts von dem was ich versuche die auf dem heap allozierten strings (char*) zu löschen!

    ~StringTable(void) {
    		/*
    		std::for_each (table.begin(), table.end(), 
    					[](tPair pair) {
    						delete[] pair.second;
    				});*/
    
    		for (auto itr = table.begin (); itr != table.end (); ++itr) {
    					table.erase(itr->first);
    				}
    
    		//std::cout<<((tPair)*table.begin()).second<<std::endl;
    		//delete ((tPair)*table.begin()).second;
    		//table.erase(GetHash(((tPair)*table.begin()).second));
    
    		//table.clear();
    	}
    

    Die Einträge werden erzeugt mit:

    void StringTable::addEntry(const char* str )
    {
    	using std::cout;
    	using std::endl;
    	QHash hash = GetHash(str);
    	if (table.find (hash) != table.end())
    	{
    		cout<<"Eintrag "<<str<<" existiert bereits!"<<endl;
    		return;
    	}
    	table[hash] = strcpy (new char[strlen(str)], str);
    }
    

    Am liebsten wär mir natürlich die Lösung mit dem Lambda ganz am Anfang,
    die Versuche mit der for-schleife haben die gleichen Fehler geliefert, dies sagt mir dass das Lambda zumindest syntaktisch richtig ist.

    Meine Vermutung war eben wenn ich die Ausgabe mittels cout machen kann ich die richtige Stelle im Speicher erwischt habe und darauf dann auch mein delete absetzen kann...

    das aktuelle (erase) liefert m.M.n. nur Fehler weil es den Iterator invalidiert - doch was ist mit den anderen? es sollte doch möglich sein einfach den Pointer zu besorgen und wie man es halt kennt zu löschen... ist es aber nicht! oder ich mache hier einen Denkfehler!



  • Kannst du nicht einfach einen std::string in deine map packen? Oder zumindest std::unique_ptr benutzen?
    Dann ergibt sich die Sache mit dem Aufräumen völlig von selbst...



  • Könnte ich, allerdings ist das ja pädagogisch nicht besonders wertvoll...
    Irgendwann bin ich in einer Situation wo das nicht geht, ich möchte zumindest wissen wo mein Fehler liegt!



  • Wenn die beiden Optionen mal nicht gehen, dann bau dir deinen eigenen Smartpointer. Ich würde das Problem auf jeden Fall über RAII lösen.



  • Hi Nochmal -

    hab es gelöst,
    war ein klassischer OBO (Of by One) fehler,

    habe nur strlen(str) bytes reserviert, was das terminierende '\0' nicht einschließt -

    habe folgendes geändert :

    void StringTable::addEntry(const char* str )
    {
    .
    .
    //table[hash] = strcpy (new char[strlen(str)], str);
    table[hash] = strcpy (new char[strlen(str) + 1], str);
    .
    .
    }
    

    Was mich verwundert ist dass das cout trotzdem funktioniert hat...
    ich nehme an das mich der debug-modus von VC davor "beschützt" hat und dass es im release-mode auf jeden Fall deswegen geknallt hätte 🙄

    Bin auf jeden Fall froh dass das jetzt gelöst ist und ich beruhigt schlafen kann - danke dir für deine Hilfe! 👍 🤡


Anmelden zum Antworten