std::map unterschiedliche Typen aufnehmen lassen

Schnelle objektorientierte, kompilierende Programmiersprache.
Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: std::map unterschiedliche Typen aufnehmen lassen

Beitrag von fat-lobyte » Sa Aug 15, 2009 12:32 pm

Dirty Oerti hat geschrieben:Das Problem liegt, glaube ich, einfach irgendwo IN OpenSceneGraph, bei der Weiterleitung der Daten an das SDL-Fenster.
Zeiger übergebe ich nicht, zumindest nicht direkt.
Ich habe eine Viewer-Instanz, deren Member frame() aufgerufen wird (werden muss).
Evtl. kommt das Problem auch daher, dass diese Viewer-Instanz über einen osg::ref_ptr<> im ursrpünglichem Thread erstellt wird. Die ref_ptr sollen eigentl "Threadsicher" sein, aber ich weiß nicht...
Du hast mehrere Threads? Das ist immer ein ziemlich heißer Tip. Hatte mal nen echt gemeinen Bug: segmentation fault IN libpango. Hat mich ziemlich gewundert, weil ich diese Bibliothek nicht verwende. Debugging Symbole von allem installiert was es gibt, gegoogelt und dann Hatte ichs: libpango wurde von GTK, GTK von wxWidgets verwendet. Ich hatte eine Funktion aus nem anderen Thread aufgerufen, die man nicht aufrufen darf, und schon hatte ich den Salat ^^
Die Moral von der Geschicht: sieh dir nochmal die Schnittstellen zwischen den Threads an


Dirty Oerti hat geschrieben:Naja, es bedeutet für mich deutlich weniger Schreibarbeit. Ich hab auf diese Art 3 Memberfunktionen, mit denen ich beliebige Objekte hinzufügen, suchen und wieder entfernen kann.
Ich füge ja nur "bekanntes" in diese Map ein, und suche folglich nur nach Bekanntem.
Und was ist da der Vorteil? Hast du die Objekte nicht sowieso schon irgendwo im Code? Sorry, ich verstehs immer noch nicht ganz verstanden. Wieso ist es weniger schreibarbeit? Was sparst du dir dadurch konkret? Oder gehts hier ums suchen?
Die Map ist also keineswegs dynamisch zur Laufzeit beliebig veränderbar.
Dann darfst du nicht vergessen dass die "Bequemlichkeit" dir Laufzeit kostet, denn dein bequemer std::map::operator[] (std::string&) aufruf ruft erstmal ne suche auf. Wenn dein Map groß ist, dann kostet das. Ich persönlich versuche tunlichst alles was zur Kompilierzeit bekannt ist auch in fixen Code zu gießen, aber jeder wie er mag.
Dazu müsste ich im String wohl noch eine Typbeschreibung einbauen, nach der dann (aus einer festgelegten Menge an Typen) der Typ bestimmt wird. Das ist mir jetzt aber zu aufwendig.
Also erstens musst du wissen, dass du in Maps nur Objekte mit "gleichen Eigenschaften" reingeben kannst. "gleichen Eigenschaften" bedeutet zum Beispiel sowas wie ne Basisklasse.

Außerdem musst du ja beim "rausholen" und beim "suchen" was damit machen, und zumindest das sollten die Ojekte gemeinsam haben. Das heißt also du könntest entweder nen void* Zeiger haben und dann alles richtig casten. Das ist sehr sehr (sehr) unschön, und fehleranfällig. Etwas besser wirds wenn du eben einen Basisklassenzeiger hast, und dann nach den jeweiligen Objekten castest. Sowas hab ich schon mal gemacht, sieht ungefähr so aus:

Code: Alles auswählen

void BlaBlub::handleCommand(const ControlCommand& cmd)
{
    // determine actions depending on the id of the command
    switch ( cmd.id )
    {
        // ...
 
        case ControlCommand::ID_DISCONNECT:
            disconnect();
            break;

        case ControlCommand::ID_PRINT_MSG:
        {
            const MessageCommand<ControlCommand::ID_PRINT_MSG>& cmd_msg =
                static_cast<const MessageCommand<ControlCommand::ID_PRINT_MSG>&> (cmd);

            printMessage(L"<< " + cmd_msg.msg);
            break;
        }

        case ControlCommand::ID_SEND_MSG:
        {
            const MessageCommand<ControlCommand::ID_SEND_MSG>& cmd_msg =
                static_cast<const MessageCommand<ControlCommand::ID_SEND_MSG>&> (cmd);

            sendMessage(cmd_msg.msg);
            break;
        }
        default:
            printMessage(L"Invalid command!");
            break;

    }
}
Nicht von den namespaces und templates verwirren lassen, es geht einfach nur ein Enum in der Basisklasse, und je nachdem welchen wert das enum hat wird in die richtige abgeleitete Klasse gecastet.
So, das ist aber eigentlich gar nicht hübsch. Es ist in wahrheit nichts anderes als RTTI (Runtime Type Information), und man könnte stattdessen den [urlhttp://en.wikipedia.org/wiki/Typeid]typeid[/url] operator verwenden. Frag nicht wie, hab keine Ahnung, will ich auch nicht haben.

So, das war Möglichkeit 1:

Möglichkeit 2:
Ich hab mal beim durchsehen der Boost Bibliotheken Boost.Any gefunden. Das sieht so ziemlich nach dem aus, was du brauchst. Sieh dir die Beispiele an: http://www.boost.org/doc/libs/1_39_0/do ... y/s02.html

Und: Vorrangig hat es mich interessiert, ob und wie (einfach oder schwer) so etwas realisierbar ist :)
Die Vorschläge siehst du oben. Was ich dir aber ans Herz legen will, ist folgendes:
C++ hat die nette eigenschaft dass es in vielen Fällen gedankliche Fehler, Ungereimtheiten und Widersprüche aufzeigt. Manchmal ist es schwer vom Compilerfehler auf den Gedankenfehler zu kommen, aber mir kommt vor das ist so ein Fall. Ich persönlich höre bei nicht Trivialen Fehlern auf zu programmieren, und überdenke nochmal: stimmt mein Konzept? Ist mein Design widerspruchsfrei? Geht das überhaupt?
Mal ganz von C++ abgekoppelt:
Eine Sammlung von Objekten ist für dich nur Sinnvoll, wenn du was damit tun kannst; um etwas damit tun zu können musst du wissen was diese Objekte sind. Wenn du eine Büchersammlung hast, kannst du sie reinstellen, Lesen und Wegschmeissen. Dein "std::map<bla, void*>" kann man mit einer "Papiersammlung" vergleichen. Was für ein Papier? Bücher? Zeitschriften? Bilder? Kartons? Klopapier? Tapete? Keine Ahnung - du weißt es ja nicht mehr. Du kannst sie nur noch reingeben und wieder rausnehmen. "nützlich" ist diese Sammlung für dich aber nicht! Und ich denke so ähnlich ists hier mit deinen Objekten. Korrigiere mich, wenn ich falsch liege.

Du solltest zuerst definieren was deine Sammlung ist, wozu sie gut ist und was du damit tun willst. Erst dann kann man über die Implementierung nachdenken.


Sorry für den langen Post, hab lang nix mehr geschrieben und jetzt muss ich überall meinen Senf dazu geben und mir meine Meinung von der Seele schreiben ;-)
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: std::map unterschiedliche Typen aufnehmen lassen

Beitrag von Dirty Oerti » Sa Aug 15, 2009 12:53 pm

fat-lobyte hat geschrieben:Sorry für den langen Post, hab lang nix mehr geschrieben und jetzt muss ich überall meinen Senf dazu geben und mir meine Meinung von der Seele schreiben ;-)
Kein Problem ;) Und nicht wundern, dass ich von hinten anfang^^

Ok:
fat-lobyte hat geschrieben:Dann darfst du nicht vergessen dass die "Bequemlichkeit" dir Laufzeit kostet, denn dein bequemer std::map::operator[] (std::string&) aufruf ruft erstmal ne suche auf. Wenn dein Map groß ist, dann kostet das. Ich persönlich versuche tunlichst alles was zur Kompilierzeit bekannt ist auch in fixen Code zu gießen, aber jeder wie er mag.
Ich glaube, du verstehst mich nicht. Mir ging es hierbei nicht darum, ein perfektes, wirklich verwendbares Konzept zu finden. Das, was ich hier programmiert habe ist nicht dazu gedacht, wirklich Verwendung zu finden. :)
Es ist reines Interesse, reine Neugier.
fat-lobyte hat geschrieben:Die Vorschläge siehst du oben. Was ich dir aber ans Herz legen will, ist folgendes:
C++ hat die nette eigenschaft dass es in vielen Fällen gedankliche Fehler, Ungereimtheiten und Widersprüche aufzeigt. Manchmal ist es schwer vom Compilerfehler auf den Gedankenfehler zu kommen, aber mir kommt vor das ist so ein Fall. Ich persönlich höre bei nicht Trivialen Fehlern auf zu programmieren, und überdenke nochmal: stimmt mein Konzept? Ist mein Design widerspruchsfrei? Geht das überhaupt?
Mal ganz von C++ abgekoppelt:
Eine Sammlung von Objekten ist für dich nur Sinnvoll, wenn du was damit tun kannst; um etwas damit tun zu können musst du wissen was diese Objekte sind. Wenn du eine Büchersammlung hast, kannst du sie reinstellen, Lesen und Wegschmeissen. Dein "std::map<bla, void*>" kann man mit einer "Papiersammlung" vergleichen. Was für ein Papier? Bücher? Zeitschriften? Bilder? Kartons? Klopapier? Tapete? Keine Ahnung - du weißt es ja nicht mehr. Du kannst sie nur noch reingeben und wieder rausnehmen. "nützlich" ist diese Sammlung für dich aber nicht! Und ich denke so ähnlich ists hier mit deinen Objekten. Korrigiere mich, wenn ich falsch liege.

Du solltest zuerst definieren was deine Sammlung ist, wozu sie gut ist und was du damit tun willst. Erst dann kann man über die Implementierung nachdenken.
fat-lobyte hat geschrieben:Und was ist da der Vorteil? Hast du die Objekte nicht sowieso schon irgendwo im Code? Sorry, ich verstehs immer noch nicht ganz verstanden. Wieso ist es weniger schreibarbeit? Was sparst du dir dadurch konkret? Oder gehts hier ums suchen?
*grins* Wie gesagt, das ist nicht dazu da, wirklich iwie Sinn zu ergeben oder gut zu sein. Es geht hier darum, was möglich ist.
Was ich testen wollte:

Code: Alles auswählen

map.add(ding1);
map.add(ding2);
map.add(anderesding1);
map.add(sonstwas);
Anstatt:

Code: Alles auswählen

map.add_ding(ding1);
map.add_ding(ding2);
map.add_anderesding(anderesding1);
//...
fat-lobyte hat geschrieben:es geht einfach nur ein Enum in der Basisklasse, und je nachdem welchen wert das enum hat wird in die richtige abgeleitete Klasse gecastet.
So hätte ich vermutlich dann weitergemacht ;)

Boost.any interessiert mich in dem Fall jetzt nicht, wie gesagt, keine "Produktividee" :)
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Antworten