std::vector aus std::queue's



  • Hallo zusammen, ich versuche gerade ein Template zu erzeugen, das ein Vektor aus Queue's erzeugt. Also zunächst die Klasse:

    class Node {
        
        public:
        
        //Node(T, int anz = 5) : BasePtr(T, anz) {
        Node(T myType, int anz = 5) {
    
            this->elementCnt = 5;
            std::queue<T> q;
            q.push(myType);
            Base.push_back(q);
            //Base.push_back(std::queue<T> q.push(myType));
            
        }
    
        private:
        int         elementCnt;
        std::vector<std::queue<T>> Base;
    
    };
    

    Und ich erzeuge dann 2 verschiedene Instanzen für verschiedene Datentypen (stark vereinfacht um das Problem hervorzustellen:

    int main(int argc, char *argv[])
    {
        int n = 5;
    
        Node<const char*> v("hallo",n);
        Node<int> d(7,n);
    
        return 0;
    }
    

    Das funktioniert auch. Ich frage mich nur, ob man das auch etwas einfacher haben kann, nämlich ohne das temporäre std::queue Objekt im Konstruktor. So das man direkt in den Vektor eine anonyme Queue einfügen kann? Das könnt so aussehen:

    Base.push_back(std::queue<T> q.push(myType));
    

    funktioniert so aber nicht. Aber wie könnte man das machen?
    Vielen Dank


  • Mod

    Base.push_back(std::queue<T>({myType}));
    

    Aber wenn wir schon so weit sind, die Queue mit einer initializer list zu füttern, können wir auch ganz diese temporäre, namenlose Queue vermeiden:

    #include <initializer_list>
    
    [...]
    
    Base.emplace_back(std::initializer_list<T>{myType});
    

    All das (inklusive deiner jetzigen Variante) sollte für einen optimierenden Compiler aber leicht durchschaubar sein und dürfte zum selben Maschinencode führen. Es ist daher eigentlich nur ein Unterschied welche Variante zu am verständlichsten zu Lesen findest. Rein theoretisch enthält die letzte Variante aber die kleinste Anzahl an Schritten und Objekten, auch wenn sie von der Anzahl der Zeichen her die längste ist.



  • @SeppJ sagte in std::vector aus std::queue's:

    #include <initializer_list>

    Vielen Dank, genau nach sowas habe ich gesucht. C++ denkt wirklich an alles 😉
    Ich habe noch diesen Blog Eintrag gefunden: push_back vs. emplace_back



  • Ich hätte noch eine Folgefrage, bezüglich des Auslesens der Daten in diesem Fall. Wir haben hier ein Beispiel von geschachtelten STL Datentypen. Wie würde ich am elegantesten und vor allem "Ressourcen schohnensten" diese wieder heraus puhlen?
    In meinem oben beschriebenen Fall habe ich jetzt also ein

    std::vector<std::queue<T>> Base;
    

    Ein STL Vector, welcher in jedem seiner Elemente eine STL Queue hat. Das kann auch eine Liste sein, eine Dqueue oder eine Map...
    Wenn ich mit einer Schleife nun durch den Vector gehe und dann iterativ in jede Queue und aus dieser dann den Inhalt auslese habe ich das folgendermaßen gemacht:

    void printVector() {
            for(auto pos: Base) {
                std::queue<T>& ref = pos;
                std::cout << ref.back() << std::endl;
            }
    }
    

    In meinem Fall ist jetzt nur in der 1. Queue des 1. Vectors ein String. Und das lässt sich compilieren, ohne Warnungen und läuft.

    Aber ich frage mich ob es noch einen anderen besseren Weg gibt, wie man das macht: durch Casten der iteratoren?

    Vielen Dank

    P.S. vielleicht gibt es irgendwo eine gute Quelle mit Beispielen?



  • @CalibanX sagte in std::vector aus std::queue's:

    for(auto pos: Base) {

    Das macht dir eine Kopie!

    Besser: for (const auto &pos : Base) ... - achte auf das & (und warum nicht const?)
    (by the way, ich finde den Namen Base für eine Vector-Variable sehr verwirrend, da ich an eine Basisklasse (nicht Variable) denken muss)

    std::queue<T>& ref = pos; - diese Zeile ist irgendwie überflüssig - dann kannst du die Loop-Variable auch gleich ref nennen.

    std::cout << ref.back() << std::endl; - das geht nur, wenn die queue nicht leer ist! Da fehlt mindestens ein check. Außerdem brauchst du in so einer Loop sicher kein std::flush nach jeder Zeile.



  • @wob sagte in std::vector aus std::queue's:

    (by the way, ich finde den Namen Base für eine Vector-Variable sehr verwirrend, da ich an eine Basisklasse (nicht Variable) denken muss)

    Ja der Name ist irgendwo woanders raus gefallen. Das ganze ist jetzt nur noch experimentell

    std::queue<T>& ref = pos; - diese Zeile ist irgendwie überflüssig - dann kannst du die Loop-Variable auch gleich ref nennen.

    Warum ist das Überflüssig, das ist der eigentliche Inhalt meiner Frage, ich muss doch ein Cast machen, um dem Compiler klarzumachen daß in dem Vektorelement ein Queueelement ist und ich jetzt mit dessen Methoden den Inhalt rausholen kann/muß

    std::cout << ref.back() << std::endl; - das geht nur, wenn die queue nicht leer ist! Da fehlt mindestens ein check. Außerdem brauchst du in so einer Loop sicher kein std::flush nach jeder Zeile.



  • @CalibanX Nein, der Compiler weiß schon, dass da Queues in dem Vektor sind.

    for(const auto& pos : Base)

    ist nur eine einfachere Schreibweise für

    for(const std::queue& pos : Base)

    Bei range based for Schleifen hast du nämlich keine Iteratoren an der Hand, sondern direkt die Objekte in dem Vektor. Und, auto deduziert nur den korrekten Typen.


Anmelden zum Antworten