Die Anzahl der Objekte abfragen?



  • class foo
    {
    private:
        static unsigned number;
    
    public:
        static void output()
        {
            cout << number;
        }
        foo() // Konstruktor
        {
            ++number;
        }
    };
    unsigned foo::number = 0;
    


  • Gugelmoser schrieb:

    class foo
    {
    private:
        static unsigned number;
    
    public:
        static void output()
        {
            cout << number;
        }
        foo() // Konstruktor
        {
            ++number;
        }
    };
    unsigned foo::number = 0;
    

    Es koennen auch Objekte zerstoert werden. Das fehlt in deinem Code.

    Ausserdem waere es wohl besser gewesen, cobb haette zuerst selber etwas probiert.



  • Erst mal vielen Danke für die schnelle Antwort, ich bin wie folgt vorgegangen.
    Ich habe eine statische Variable erstellt, dann im meinem Standard Konstruktor diese Variable inkrementiert genau das gleiche habe ich auch in meinem Copy Konstruktor und überladendem Konstruktor gemacht und in Destruktor habe ich die Variable dekrementiert. Am ende eine funktion erstellt die mir die statische Variable ausgibt.

    // Header Datei
    class Fraction
    
    private: 
    
    static int counter;
    
    public:
    //Standard Konstruktor
    
    Fraction();
    
    //Überladener Konstruktor
    
    Fraction(int z, int n);
    
    //Copy Konstruktor
    Fraction(const Fraction& b);
    
    //Destruktor
    ~Fraction();
    
    static void getNumberofObjects(){cout << counter;}
    
    // cpp. Datei
    
    Fraction::Fraction(){++counter;}
    ~Fraction::Fraction(){--counter;}
    int Fraction::counter = 0; // Dieses Punkt verstehe ich nicht, warum ich die Variable ausserhalb der Klasse initialisieren soll???
    

    Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???
    Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!



  • cobb schrieb:

    Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???

    Ja. In jedem Konstruktor.

    cobb schrieb:

    Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!

    Muß sie nicht. Ist aber oft praktischer, daß man Fraction::getNumberofObjects() aufrufen darf, ohne ein konkretes Objekt in Händen zu halten. Dazu das static.


  • Mod

    cobb schrieb:

    Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???

    Ja, denn in beiden Fällen wird ein neues Objekt erzeugt, der Standardkonstruktor wird dabei gar nicht angefasst.

    Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!

    Muss nicht, aber sollte. Die Eigenschaft wie viele Objekte einer Klasse es gibt, ist eine Eigenschaft der Klasse, nicht eines einzelnen Objekts. Das merkst du z.B. daran, dass in der Methode nur auf statische Eigenschaften der Klasse zugegriffen wird.

    edit: Zu langsam, mal wieder, leider. Jetzt habe ich neben cooky und seldon auch noch volkard, der immer einen Tick schneller ist.



  • Vielen Dank ihr habt mir sehr geholfen!!!



  • SeppJ schrieb:

    edit: Zu langsam, mal wieder, leider. Jetzt habe ich neben cooky und seldon auch noch volkard, der immer einen Tick schneller ist.

    // ==UserScript==
    // @name SeppJ's Posting Helper
    // @namespace SeppJ
    // @description Adds "edit: Zu langsam mal wieder."
    // @include http://www.c-plusplus.net/forum/quote*
    // ==/UserScript==
    // Code geklaut von http://userscripts.org/scripts/review/118944
    
    String.prototype.startsWith = function(s)
    {
    	return this.substr(0, s.length) == s;
    }
    
    var edit = document.getElementsByTagName("textarea")[0];
    
    if(edit.innerHTML.startsWith("[quote="))
    {
    	edit.innerHTML += "\n\n\nedit: Zu langsam mal wieder.\n";
    	edit.focus();
    }
    


  • template <typename>
    struct tracked
    {
            tracked()  { ++object_count_; }
            tracked(tracked const&) { ++object_count_; }
            tracked(tracked&&) { ++object_count_; }
    
            ~tracked() { --object_count_; }
    
            static std::size_t object_count() { return object_count_; }
    
    private:
            static std::atomic<std::size_t> object_count_;
    };
    
    struct foobar : tracked<foobar>
    {
            ...
    };
    

    Mal so ein Vorschlag. Was haltet ihr davon?



  • 314159265358979 schrieb:

    Was haltet ihr davon?

    Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:

    • Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.
    • Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.
    • Die Vererbung sollte privat sein.
    • Ohne Grund thread-safe ist wohl eine schlechte Idee.


  • davonhalter schrieb:

    Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:

    Jo, das stimmt. Aber ein Lob schadet nie, davon gibts eh viel zu wenige :p

    davonhalter schrieb:

    Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.

    Aber es wäre denkbar, dass in der abgeleiteten Klasse einer geschrieben wird.

    davonhalter schrieb:

    Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.

    Okay, da hast du Recht. Der Dtor allerdings auch.

    davonhalter schrieb:

    Die Vererbung sollte privat sein.

    Und wie rufst du dann T::object_count() auf? 🤡

    davonhalter schrieb:

    Ohne Grund thread-safe ist wohl eine schlechte Idee.

    Finde ich nicht. Wenn, dann wird sowas doch sowieso nur zu Debuggingzwecken verwendet. Da sollte man einen Fehler durch mehrere Threads von vornherein ausschließen.



  • 314159265358979 schrieb:

    davonhalter schrieb:

    Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:

    Jo, das stimmt. Aber ein Lob schadet nie, davon gibts eh viel zu wenige :p

    Ich bin mal nicht so. Gratulation für die Leistung, eine so simple wie geniale Möglichkeit gefunden zu haben, das Tracking in eine Basisklasse auszulagern. Und dabei noch die Nötigkeit von CRTP festgestellt zu haben 😉

    314159265358979 schrieb:

    davonhalter schrieb:

    Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.

    Aber es wäre denkbar, dass in der abgeleiteten Klasse einer geschrieben wird.

    Genauer: Der Move-Konstruktor wird u.a. dann nicht erstellt, wenn die Klasse einen Kopierkonstruktor hat. Das heisst, tracked ist nicht und wird nie verschiebbar sein. In den Fällen wird dann immer der Kopierkonstruktor aufgerufen, der in diesem Fall das richtige erledigt.

    Was in foobar passiert interessiert nicht.

    314159265358979 schrieb:

    davonhalter schrieb:

    Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.

    Okay, da hast du Recht. Der Dtor allerdings auch.

    Stimmt. Sogar alle Member ausser object_count_.

    314159265358979 schrieb:

    davonhalter schrieb:

    Die Vererbung sollte privat sein.

    Und wie rufst du dann T::object_count() auf? 🤡

    Mit einem

    using tracked<foobar>::object_count;
    

    Die Gefahr ein tracked<foobar> aus foobar zu erhalten stufe ich schlimmer ein.

    314159265358979 schrieb:

    davonhalter schrieb:

    Ohne Grund thread-safe ist wohl eine schlechte Idee.

    Finde ich nicht. Wenn, dann wird sowas doch sowieso nur zu Debuggingzwecken verwendet. Da sollte man einen Fehler durch mehrere Threads von vornherein ausschließen.

    Gut, das kann man sehen, wie man will.



  • davonhalter schrieb:

    Die Gefahr ein tracked<foobar> aus foobar zu erhalten stufe ich schlimmer ein.

    Bleib mal realistisch.



  • So, nach nun einer Stunde Überlegen hab ich so ziemlich alles umgekrempelt. Das Problem mit dem bisherigen Ansatz ist, dass er mit Vererbungshierarchien nicht zurechtkommt. Beispiel: 2 Klassen base und derived, beide ebenfalls von tracked<T> abgeleitet. In dervied wäre object_count nun ambigious.

    Der neue Ansatz düfte mit allen denkbaren Hierarchien funktionieren.

    template <typename>
    std::size_t object_count();
    
    template <typename Derived>
    struct tracked
    {
    	friend std::size_t object_count<Derived>();
    
    protected:
    	tracked() { ++object_count; }
    	tracked(tracked const&) { ++object_count; }
    	~tracked() { --object_count; }
    
    private:
    	static std::atomic_size_t object_count;
    };
    
    template <typename Derived>
    std::atomic_size_t tracked<Derived>::object_count;
    
    template <typename T>
    std::size_t object_count()
    {
    	static_assert(std::is_base_of<tracked<T>, T>::value, "instances of this type are not tracked");
    	return tracked<T>::object_count;
    }
    

    object_count ist nun zu einer freien Funktion geworden. Außerdem hat die Klasse tracked keine public Member mehr, was bedeutet, dass man auch einfach private von ihr erben kann und sie somit nicht mehr in ein tracked konvertierbar ist. 😉

    Verwendet sich dann so:

    struct base : private tracked<base> {};
    struct derived : base, private tracked<derived> {};
    
    int main()
    {
    	derived d;
    
    	std::cout << object_count<base>()    << '\n'
    	          << object_count<derived>() << '\n';
    }
    

    http://ideone.com/ltR7q
    Gar nicht mal so einfach, wenn man es ordentlich machen will. 🙂


Anmelden zum Antworten