Klassen Instanz richtig erstellen?



  • Guten Abend,
    ich habe mir seit längeren die Frage gestellt wie man eine Klassen Instanz richtig erstellt?
    Ich weiß das hört sich jetzt komisch an aber ich wollte einfach mal wissen ob es Unterschiede gibt(siehe Code Beispiel) und wenn ja welche? Und welche "Variante" man benutzen sollte.

     ... Code ... 
    class Test{};
    Test test;//Variante 1
    Test * test = new Test;//Variante 2
    Test * test = new Test();//Variante 3
    

    Danke im voraus
    MFG Killerzwerg



  • Das ist sogar viel komplizierter, als man denkt 😉 Es gibt tatsächlich Unterschiede zwischen Variante 2 und Variante 3, und das wissen auch etlich erfahrene C++ Enwickler nicht. Schau in den Standard für Details, das ist im Detail auch für mich zu kompliziert, um das auswendig zu wissen.
    Grundsätzlich solltest du Variante 1 bevorzugen, falls möglich. Dynamischer Speicher ist deutlich langsamer.
    Außerdem sind Varianten 2 und 3 an sich schon suboptimal, man sollte keine rohen besitzenden Zeiger benutzen. Das führt zu vielen Problemen, und es würde zu weit führen, das auf die Schnelle zu erklären. Hier sollte man shared_ptr oder unique_ptr mit den entsprechenden make_... Funktonen bevorzugen. "new" sollte im Code möglichst gar nicht vorkommen.



  • @mechanics sagte in Klassen Instanz richtig erstellen?:

    Das ist sogar viel komplizierter, als man denkt 😉 Es gibt tatsächlich Unterschiede zwischen Variante 2 und Variante 3, und das wissen auch etlich erfahrene C++ Enwickler nicht. Schau in den Standard für Details, das ist im Detail auch für mich zu kompliziert, um das auswendig zu wissen.

    Ist doch eigentlich ganz einfach: mit Klammern gibt es Value-Initialisierung, ohne nicht. Beispiel:

    struct Test { int i; }
    auto t1 = new Test;
    auto t2 = new Test();
    // t1->i ist uninitialisiert
    // t2->i ist 0
    

    Aber wie Mechanics schon sagte, statt new besser std::make_unique verwenden!

    Dynamischer Speicher ist deutlich langsamer.

    Naja... So pauschale Aussagen finde ich immer fragwürdig. Es ist ja derselbe Speicherchip. "Langsam" ist ggf. des "new". Und danach ist eigentlich nur der Speicher langsam, der nicht in irgendeinem Cache des Prozessors ist. Bevor du mit dem Geschwindigkeitsargument kommst, solltest du sicher sein, dass das Problem daher rührt. Normalerweise ist der Use-Case ja entscheidend, also brauche ich das Objekt länger als die Funktion lebt oder nicht - und natürlich die Frage, wie groß es ist, also passt es sinnvoll auf den Stack oder nicht. Große Objekte würde ich standardmäßig immer im Freispeicher anlegen und das nur in Ausnahmefällen ändern.



  • @wob Interessenshalber, ab wann ist für dich ein Objekt groß?



  • @wob sagte in Klassen Instanz richtig erstellen?:

    mit Klammern gibt es Value-Initialisierung, ohne nicht. Beispiel:

    Das gilt vielleicht für PODs.

    @wob sagte in Klassen Instanz richtig erstellen?:

    Ist doch eigentlich ganz einfach

    struct Test { Test() {}; int i; };
    

    und nu?

    @mechanics sagte in Klassen Instanz richtig erstellen?:

    Das ist sogar viel komplizierter, als man denkt Es gibt tatsächlich Unterschiede zwischen Variante 2 und Variante 3, und das wissen auch etlich erfahrene C++ Enwickler nicht. Schau in den Standard für Details, das ist im Detail auch für mich zu kompliziert, um das auswendig zu wissen.

    qft!



  • @schlangenmensch sagte in Klassen Instanz richtig erstellen?:

    @wob Interessenshalber, ab wann ist für dich ein Objekt groß?

    Keine Ahnung, schwierige Frage, hängt davon ab, möchte mich nicht festlegen. In der Regel sind die "großen" Daten ja eh wieder in Objekten wie einem std::vector, die dann ihrerseits automatisch die Daten in den Freispeicher legen. Aber das gilt nicht immer, vor allem nicht bei Arrays (ob nun C-Style oder std::array).

    Aber wenn ich z.B. ein double x[5000] habe, würde ich wohl über make_unique<double[]>(5000) nachdenken. Und wenn die Funktion noch rekursiv aufgerufen wird, dann schon bei deutlich kleineren Werten.



  • @wob sagte in Klassen Instanz richtig erstellen?:

    Naja... So pauschale Aussagen finde ich immer fragwürdig. Es ist ja derselbe Speicherchip. "Langsam" ist ggf. des "new".

    Das habe ich jetzt etwas schlampig formuliert, aber sollte eigentlich klar sein, dass ich eben "new" meine. Dynamische Speicherverwaltung im Gegensatz zu "Stackvariablen". Nagele mich nicht wieder wegen dem Begriff fest, sollte denke ich klar sein, was ich meine.
    Und die pauschale Empfehlung, wegen Performance möglichst kein new zu verwenden (schon klar, der konkrete Use Case ist erstmal wichtiger) find ich sogar wichtig. Viele Entwickler, die erst Erfahrungen mit Sprachen wie Java oder C# gemacht haben (mich eingeschlossen) haben erstmal kaum Bedenken, überall new hinzuschreiben. Und das ist einer DER Performancekiller.



  • Ja, wie viel Stack man in einer Funktion verbraten darf ist keine ganz einfache Frage. In normalen "dicker PC" Anwendungen, die mit Standard Stackgrössen ab 1MB arbeiten, akzeptiere ich auch mal 64kB. WENN die Funktion keinerlei Callbacks aufruft, nicht rekursiv ist und in einer "low leveligen" Utility Library. Also beispielsweise ne Funktion die irgendwas in einen Puffer formatiert und dann bloss noch eine "schreib das mal ins File" Funktion aufruft.

    In anderen Situationen können 100 Byte schon viel sein.