Boost PTR Container und Algorithmen



  • Hallihallo

    Im Artikel http://www.c-plusplus.net/forum/viewtopic-var-t-is-146604.html steht das die Algorithmen das Arbeitspferd der STL sind.

    Nun bin ich am überlegen ob es Sinn macht wenn ich z.B. einen Boost PTR Vector habe und ich das Objekt des Containers haben möchte welches in einer Membervariable einen bestimmten Wert hat(z.b. ID-String o.ä. - d.h. der String ist in der Liste der Objekte einzigartig). Lohnt es sich da nen Algorithmus draufzuschicken oder ist das too much und sollte man lieber einfach iterieren und per hand überprüfen?

    Vorallem dürfte doch ein einfaches iterieren über die Elemente mit einem entsprechendem return bei einem Fund schneller sein als mit einem Algorithmus komplett drüber zu gehen und bei einem Fund trotzdem weiter zu suchen, oder irre ich mich da?

    [habe bisher noch nicht mit Algorithmen über Containern gearbeitet]

    Danke im voraus für die Antworten.



  • Die Standard Algorithmen machen solche (lächerlichen) Optimierungen bereits. Für so einen einfachen Such-Algorithmus wirst du mit "Selber-Drüber-Iterieren" nie besser sein als der Standard Algorithmus. Nur in speziellen Fällen, in denen du dir sicher bist, dass erstens die Stelle tatsächlich Optimierunsbedarf hat (Profiler, ist die Stelle überhaupt kritisch?) und zweitens du tatsächlich in der Lage bist schnelleren Code zu schreiben.

    In deinem Fall könnte ein find_if passend.

    Ein Standard Algorithmus ist nie "too much", meistens sogar die etwas faulere Variante (im Sinne von weniger tippen). Außerdem kannst du dir sicher sein, dass du zumindest in dem Code keinen Fehler gemacht hast, da er ja nicht von dir stammt 😉

    Gruß
    Don06



  • Don06 schrieb:

    Ein Standard Algorithmus ist nie "too much", meistens sogar die etwas faulere Variante (im Sinne von weniger tippen).

    Außerdem erhöht es die Lesbarkeit des Codes. Ein find_if ist viel aussagekräftiger, als irgendeine for -Schleife.



  • Okay danke für die Tipps.
    Jetzt fällt mir natürlich bei find_if auf das die Prädikats-Funktion nur einen Parameter übernimmt (das entsprechende Element aus dem Container jeweils). Im Internet gibt es viele Beispiele wo find_if auf einen Konstanten Wert überprüft, nun ist es bei mir aber so das ich auf einen Variablen Wert überprüfen möchte - ist es irgendwie möglich einen 2. Parameter einzuführen?

    (ich habe gesehen das es in einigen Beispielen [z.b. http://www.willemer.de/informatik/cpp/stl.htm bei Funktionsobjekten] nicht mit einer Einfachen Funktion sondern mit einer Klasse gearbeitet wurde - klinkt logisch aber da geht die Übersichtlichkeit des find_if doch sehr verloren)



  • FunMaker schrieb:

    (ich habe gesehen das es in einigen Beispielen [z.b. http://www.willemer.de/informatik/cpp/stl.htm bei Funktionsobjekten] nicht mit einer Einfachen Funktion sondern mit einer Klasse gearbeitet wurde - klinkt logisch aber da geht die Übersichtlichkeit des find_if doch sehr verloren)

    Ja, Funktionsobjekte schmälern die Übersichtlichkeit leider manchmal 😞 Ich lasse das in solchen Fällen meinen Bauch entscheiden..



  • nicht mit einer Einfachen Funktion sondern mit einer Klasse gearbeitet wurde - klinkt logisch aber da geht die Übersichtlichkeit des find_if doch sehr verloren

    In wiefern sind den da Funktionen besser?



  • FunMaker schrieb:

    Jetzt fällt mir natürlich bei find_if auf das die Prädikats-Funktion nur einen Parameter übernimmt (das entsprechende Element aus dem Container jeweils). Im Internet gibt es viele Beispiele wo find_if auf einen Konstanten Wert überprüft, nun ist es bei mir aber so das ich auf einen Variablen Wert überprüfen möchte - ist es irgendwie möglich einen 2. Parameter einzuführen?

    Was für einen variablen Wert willst du denn prüfen? Prädikate sollten allgemein stateless sein, soll heißen das Funktionsobjekt darf z.B. nicht mitzählen wie oft es den Vergleich schon angestellt hat o.ä.
    Was aber geht sind Parameter die du den Prädikaten mitgibst und die sich nicht ändern, z.B.:

    int main()
    {
       std::vector<Point3D> p3dVec;
       FillP3dVec();
    
       //Prädikat:
       struct CompareXCoords
       { 
          CompareXCoords(double compareTo) : value(compareTo) {}
          bool operator()(Point3D const& p3d) { return value == p3d.getX();}
       private:
          double value;
       };
    
       Point3D& xIs0 = *( std::find_if(p3dVec.begin(), p3dVec.end(),CompareXCoords(0.0)) );
       Point3D& xIs6 = *( std::find_if(p3dVec.begin(), p3dVec.end(),CompareXCoords(6.0)) );
    }
    

    Ich find das mit den Funktionsobjekten übrigens meist weniger unübersichtlich als mit Funktionen: Funktionen müssen immer "irgendwo anders" definiert werden, auf jeden Fall außerhalb der Funktion in der ich sie dann an den Algorithmus übergebe. Funktoren hingegen kann ich unmittelbar vor der Benutzung definieren, als local class (vermutlich ein weniger bekanntes Feature in C++).



  • pumuckl schrieb:

    Funktoren hingegen kann ich unmittelbar vor der Benutzung definieren, als local class (vermutlich ein weniger bekanntes Feature in C++).

    Vermutlich deshalb wenig bekannt weil man es eben nicht machen darf 😉



  • pumuckl schrieb:

    Ich find das mit den Funktionsobjekten übrigens meist weniger unübersichtlich als mit Funktionen: Funktionen müssen immer "irgendwo anders" definiert werden, auf jeden Fall außerhalb der Funktion in der ich sie dann an den Algorithmus übergebe.

    Übersichtlicher als Funktionen sind Funktionsobjekte meistens schon, aber die Frage ist hier ja, ob "inline-Code" nicht lesbarer/sinnvoller wäre.

    So wie ich das verstanden habe, geht's hier um

    //Prädikat; edit: auf Wunsch von Lord Jaxom ausgelagert :)
    struct CompareXCoords
    { 
       CompareXCoords(double compareTo) : value(compareTo) {}
       bool operator()(Point3D const& p3d) { return value == p3d.getX();}
    private:
       double value;
    };
    
    Point3D foo()
    {
        ...
    
       Point3D& xIs0 = *( std::find_if(p3dVec.begin(), p3dVec.end(),CompareXCoords(0.0)) );
       return xIs0;
    }
    

    versus

    Point3D foo()
    {
        ...
    
        // Bla-Element finden und zurückgeben
        BOOST_FOREACH( const Point3D& p, p3dVec )
            if ( p.getX() == 0.0 )
                return p;
    }
    

    , wo ich persönlich wahrscheinlich die zweite Variante wählen würde.



  • Es sei nochmal darauf hingewiesen, dass erstere Variante überhaupt nicht zulässig ist 🙂



  • aber ein

    for_each(v.begin(), v.end(), cout<<_1<<endl)
    wäre zB ganz niedlich.



  • LordJaxom schrieb:

    Es sei nochmal darauf hingewiesen, dass erstere Variante überhaupt nicht zulässig ist 🙂

    Ist das dann eine MSVC-Erweiterung (mit dem geht's jedenfalls)? Und weil ich ihn grad nicht zur Hand hab: Weiß jemand, wie's mit dem GCC aussieht?

    PS: Danke Lord, Shade's Post hatte ich ganz übersehen.



  • Wie Shade bereits angedeutet hat, gibt es ja noch die dritte Variante mit Boost.Lambda.

    Point3D foo()
    {
        ...
    
       Point3D& xIs0 = *( std::find_if(p3dVec.begin(), p3dVec.end(), _1 == 0.0) );
       return xIs0;
    }
    


  • Badestrand schrieb:

    Ist das dann eine MSVC-Erweiterung (mit dem geht's jedenfalls)? Und weil ich ihn grad nicht zur Hand hab: Weiß jemand, wie's mit dem GCC aussieht?

    Laut http://www.informit.com/articles/article.aspx?p=345948&seqNum=3 lassen CodeWarrior, DigitalMars, Watcom, Borland und Microsoft das zu. GCC (4.1 und 4.4 getestet) meldet einen Fehler.



  • Don06 schrieb:

    Wie Shade bereits angedeutet hat, gibt es ja noch die dritte Variante mit Boost.Lambda.

    Richtig, Lambda vergesse ich immer. Das finde ich auch mit Abstand die beste Lösung 👍

    LordJaxom schrieb:

    Laut http://www.informit.com/articles/article.aspx?p=345948&seqNum=3 lassen CodeWarrior, DigitalMars, Watcom, Borland und Microsoft das zu. GCC (4.1 und 4.4 getestet) meldet einen Fehler.

    Schade.. Ich entwickle meistens mit dem MSVC oder GCC, Inkompatibilität ist schon was feines 😕


Anmelden zum Antworten