[solved] Instanzen einer Klasse in einer for-Schleife in ein Array packen?



  • bogus2k schrieb:

    ich bekomme dann die Fehlermeldung das es keine Funktion Player::Player() gibt.

    Aber nicht an dieser Stelle.

    Verpass deiner Klasse mal einen Default-Konstruktor.



  • Super, vielen Dank es funktioniert endlich 😉 ich war schon total frustriert!

    Kann mir noch versuchen zu erklären warum ich einen default-Konstruktor benötige? Ich verwende doch weiterhin überall nur den Player::Player(string name,int money) Konstruktor.



  • bogus2k schrieb:

    Kann mir noch versuchen zu erklären warum ich einen default-Konstruktor benötige? Ich verwende doch weiterhin überall nur den Player::Player(string name,int money) Konstruktor.

    Wenn du einen Vector von 10 Player-Objekten anlegst, müssen die doch erst einmal konstruiert werden. 😉



  • klingt logisch 😉 vielen Dank!



  • #include <vector>
    #include <iostream>
    
    class Player
    {
        static int calls;
    public:
        Player()                    { std::cout << "() ";     ++calls;}
        Player(const Player &p)     { std::cout << "(copy) "; ++calls;}
        Player(int)                 { std::cout << "(int) ";  ++calls;}
        ~Player()                   { std::cout << "~() ";    ++calls;}
    
        static void c() { std::cout << "  Calls: " << calls << "\n" << std::endl; calls =0;}
    };
    
    int Player::calls=0;
    
    int main(void)
    {
        const int count = 10;
        {
            std::cout << "vector<Player> playersRed(count):\n\t";
            std::vector<Player> playersRed(count);
            for(int i=0; i<count; ++i)
            {
                playersRed[i] = Player(1);
            }
        }
        Player::c();
    
        {
            std::cout << "vector<Player> playersGreen; + reserve(count);\n\t";
            std::vector<Player> playersGreen;
            playersGreen.reserve(count);
            for(int i=0; i<count; ++i)
            {
                playersGreen.push_back(Player(1));
            }
        }
        Player::c();
    
    }
    
    vector<Player> playersRed(count):
    	() (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() (int) ~() ~() ~() ~() ~() ~() ~() ~() ~() ~() ~()   Calls: 42
    
    vector<Player> playersGreen; + reserve(count);
    	(int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() ~() ~() ~() ~() ~() ~() ~() ~() ~() ~()   Calls: 40
    

    Viel spart vector<T>::reserve() gegenüber vector<T>(int) scheinbar nicht .. oder überseh ich da was?



  • Wenn vector::vector den std-ctor der Klasse braucht, ist es anscheinend ein resize(). Wenn das hier stimmt:

    pumuckl schrieb:

    wenn ich das richtig im Kopf hab ist reserve fuer den Compiler eh nur eine Richtlinie, keine Regel (sprich er muss nicht unbedingt den ganzen Platz reservieren).

    ist reserve ggü. resize evtl. speicherschonender. Aber ich glaube nicht, dass es viele Unterschiede in der Performance gibt.



  • #include <iostream>
    #include <vector>
    
    class Player
    {
        static int calls;
    public:
        Player()                    { std::cout << "() ";     ++calls;}
        Player(const Player &p)     { std::cout << "(copy) "; ++calls;}
        Player(int)                 { std::cout << "(int) ";  ++calls;}
        ~Player()                   { std::cout << "~() ";    ++calls;}
        Player& operator=(Player const& p) { std::cout<<"op= "; ++calls; }
    
        static void c() { std::cout << "  Calls: " << calls << "\n" << std::endl; calls =0;}
    };
    
    int Player::calls=0;
    
    int main(void)
    {
        const int count = 10;
        {
            std::cout << "vector<Player> playersRed(count):\n\t";
            std::vector<Player> playersRed(count);
            for(int i=0; i<count; ++i)
            {
                playersRed[i] = Player(1);
            }
        }
        Player::c();
    
        {
            std::cout << "vector<Player> playersGreen; + reserve(count);\n\t";
            std::vector<Player> playersGreen;
            playersGreen.reserve(count);
            for(int i=0; i<count; ++i)
            {
                playersGreen.push_back(Player(1));
            }
        }
        Player::c();
    
    }
    
    vector<Player> playersRed(count):
    	() (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) (copy) ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() (int) op= ~() ~() ~() ~() ~() ~() ~() ~() ~() ~() ~()   Calls: 52
    
    vector<Player> playersGreen; + reserve(count);
    	(int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() (int) (copy) ~() ~() ~() ~() ~() ~() ~() ~() ~() ~() ~()   Calls: 40
    

    reserve ist VIEL besser.
    man muss nur eben auch alles korrekt zählen 😉



  • dann aber auch:

    Player& operator=(Player const& p) { std::cout<<"op= "; ++calls; return *this; }
    

    😉



  • inter2k3 schrieb:

    dann aber auch:

    Player& operator=(Player const& p) { std::cout<<"op= "; ++calls; return *this; }
    

    😉

    In der Tat.
    g++ hat keine Warnung geliefert - da muss man echt -Wall machen damit er hier was sagt. Gut zu wissen.



  • Dafür erhalte ich mit VS2010 für playersRed gleich mal 70 calls, da er bei

    std::vector<Player> playersRed(count);
    

    10 mal CTOR, CCTOR und DTOR aufruft, anstatt wie G++ anscheinend nur ein Objekt zu erstellen und dieses dann 9 mal zu kopieren.



  • @inter2k3:
    Release oder Debug?



  • Release mit Compiler-Optimierungen
    Wundert mich selbst aber ich find irgendwie keine Optimierung, die da noch greifen könnte.

    Interessanterweise produziert

    std::vector<Player> playersRed(count,Player());
    

    hingegen auch nur 52 calls.



  • Also DAS ist nun wirklich seltsam.
    Bist du sicher dass du da keinen Flüchtigkeitsfehler gemacht hast bei deinem Vergleich?

    Mit VS2005 kann das fast nicht sein, da sowohl der "nur grösse" als auch der "grösse + wert" ctor intern nur die selbe _Construct_n Funktion aufrufen... Hm.
    Muss mir das gleich nochmal mit VS2010 ansehen, vielleicht haben sie da die Std.Lib. geändert (also geändert wurde sicher viel, allein schon wegen Rvalue Referenzen, aber ich sehe keinen Grund die beiden hier betroffenen Konstruktoren zu ändern).



  • Also ich kann keinen Fehler von mir erkennen:
    (hab die Ausgabefunktion leicht geändert)

    const int count = 10;
    	{	// -1-
    		std::vector<Player> A(count);
    		for (int i = 0; i!=count; ++i)
    			A[i] = Player(i);
    	}
    	Player::clearCount("std::vector<Player> A(count)");
    
    	{	// -2-
    		std::vector<Player> B;
    		B.reserve(count);
    		for (int i = 0; i!=count; ++i)
    			B.push_back(Player(i));
    	}
    	Player::clearCount("reserve + push_back");
    
    	{	// -3-
    		std::vector<Player> C(count,Player());
    		for (int i = 0; i!=count; ++i)
    			C[i] = Player(i);
    	}
    	Player::clearCount("std::vector<Player> C(count,Player())");
    
    	{	// -4-
    		std::vector<Player> D;
    		D.reserve(count);
    		std::generate_n(std::back_inserter(D),count,[]()->Player{static int val = 0; return Player(++val);});
    	}
    	Player::clearCount("reserve + generate_n + anonym func");
    
    	{	// -5-
    		std::vector<Player> D;
    		D.reserve(count);
    		std::fill_n(std::back_inserter(D),count,Player(1));
    	}
    	Player::clearCount("reserve + fill_n");
    

    Ausgabe:

    std::vector<Player> A(count)
         CTOR: 10
    CTOR(int): 10
        CCTOR: 10
         DTOR: 30
          OP=: 10
    ====total: [b]70[/b]
    
    reserve + push_back
         CTOR:  0
    CTOR(int): 10
        CCTOR: 10
         DTOR: 20
          OP=:  0
    ====total: [b]40[/b]
    
    std::vector<Player> C(count,Player())
         CTOR:  1
    CTOR(int): 10
        CCTOR: 10
         DTOR: 21
          OP=: 10
    ====total: [b]52[/b]
    
    reserve + generate_n + anonym func
         CTOR:  0
    CTOR(int): 10
        CCTOR: 10
         DTOR: 20
          OP=:  0
    ====total: [b]40[/b]
    
    reserve + fill_n
         CTOR:  0
    CTOR(int):  1
        CCTOR: 10
         DTOR: 11
          OP=:  0
    ====total: [b]22[/b]
    


  • nett was so ein kleiner Test lostritt 🙂 - ich verwende (dogmatisch) reserve() und nie .resize()/std::vector<T>(size_t) wenn ich die größen abschätzen kann 😉


Anmelden zum Antworten