Im Konstruktor andere Objekte erzeugen?



  • std::array kannst du einfach selbst schreiben. std::unique_ptr theoretisch auch, aber dafür braucht's Move-Semantik, und die gibt's erst seit C++11. Muss deine Klasse da kopiert werden? Ansonsten könnte man nämlich sowas machen:

    // my_array.hpp // einfach
    
    #ifndef MY_ARRAY_INCLUDED
    #define MY_ARRAY_INCLUDED
    
    template <typename T, std::size_t Size>
    class my_array
    {
      T data_[Size];
    public:
      T& operator [] (std::size_t i)
      {
        return data_[i];
      }
      const T& operator [] (std::size_t i) const
      {
        return data_[i];
      }
      // .. Für den Rest der Implementierung siehe http://en.cppreference.com/w/cpp oder so
      // implementier davon halt das was du brauchst
    };
    
    #endif
    
    // my_smart_ptr.hpp // Geht eigentlich nicht vernünftig mit dem alten C++, aber C++11 hast du ja nicht
    
    #ifndef MY_SMART_PTR_INCLUDED
    #define MY_SMART_PTR_INCLUDED
    
    template <typename T>
    class my_smart_ptr
    {
      T* p_;
    
    public:
      explicit my_smart_ptr(T* p = 0)
        : p_(p)
      {}
    
      ~my_smart_ptr()
      {
        delete p_;
      }
    
      T& operator * ()
      {
        return *p_;
      }
    
      const T& operator * () const
      {
        return *p_;
      }
    
      T* operator -> ()
      {
        return p_;
      }
    
      const T* operator -> () const
      {
        return p_;
      }
    
      T* get()
      {
        return p_;
      }
    
      const T* get() const
      {
        return p_;
      }
    
      // Rest nach Bedarf
    
    private:
      my_smart_ptr(const my_smart_ptr&);
      my_smart_ptr& operator = (const my_smart_ptr&);
    };
    
    #endif
    

    shared_ptr könnte man vermutlich auch mit altem C++ schreiben, aber dafür bin ich jetzt zu faul.
    Ansonsten mein Tipp: Alles neu schreiben und einen ordentlichen Compiler benutzen. 😉



  • Dann schreib halt

    struct VegLandscape {    
        Veg veggrid[xsize][ysize];
    };
    

    Einen eigenen Konstruktor brauchst du dann nicht mal mehr; der Default-Konstruktor erledigt das.



  • @cookie:
    Vielen Dank für Deine (und der anderen) Mühe!
    Ich fürchte nur, für sowas sind meine C++-Kenntnisse zu schlecht. 😞
    Man kann sich natürlich in sowas einarbeiten, aber das ganze soll eigentlich ne Diss über mein Fach geben und nicht über C++-Programmierung, das schaff ich zeitlich ja gar nicht...
    Noch ein anderer Versuch: Wenn ich die Grids tatsächlich nicht mit Pointern, sondern den Objekten selbst realisieren würde, würde das dann gehen?
    Falls ja, hab ich noch folgende Fragen (weil es analog noch andere Klassen betrifft):

    1. Wann würden die Objekte erzeugt bzw. wo muss ich deren Instanzvariablen belegen? Reicht das im Konstruktor?
    2. Die meisten Klassen der Objekte (ich nenn es mal Gridelement-Klassen) haben nur doubles oder doubles,floats und bools als Instanzvariablen. Eine Gridelement-Klasse hat aber auch Pointer auf eine Klassenhierarchie als Instanzvariable, die manchmal belegt sind, manchmal nicht (Nullpointer). Geht das dann auch? Denn dann hätt ich ja in der Gridelementklasse auch wieder Pointer drin...
    3. Eine der Gridelement-Klassen hat 45 doubles als Instanzvariable. Wenn ich nun ein Grid mit 100x100 oder gar 500x500 nehme, geht das dann speichertechnisch?
      DAnke nochmal!

    @seldon: Ja genau, das meinte ich grade



  • seldon schrieb:

    Dann schreib halt

    struct VegLandscape {    
        Veg veggrid[xsize][ysize];
    };
    

    Einen eigenen Konstruktor brauchst du dann nicht mal mehr; der Default-Konstruktor erledigt das.

    Moment mal, heisst

    susie schrieb:

    1. Die meisten Klassen der Objekte (ich nenn es mal Gridelement-Klassen) haben nur doubles oder doubles,floats und bools als Instanzvariablen.

    dass da unterschiedliche Veg Objekte in einem Grid sind ?

    Mir schiesst gerade Scott Meyers "Never treat arrays polymorphically" aus "More Effective C++" durch den Kopf ...



  • Wenn du das mit den Pointern aufgibst:

    struct blah
    {
      std::vector<std::array<Veg, ysize>> veggrid;
    
      blah()
        : veggrid(xsize) // Das hier heißt "Initialisierungsliste"
      {}
    

    Wenn du kein std::array hast, kopier einfach meinen Code von oben in eine Datei "my_array.hpp", #include die, und schreibe std::vector<my_array<Veg, ysize>>.



  • cooky451 schrieb:

    Wenn du kein std::array hast, kopier einfach meinen Code von oben in eine Datei "my_array.hpp"

    Gewinnt man denn da etwas gegenüber der Verwendung von std::vector, außer dem Schutz vor Größenänderungen ?



  • nn schrieb:

    Gewinnt man denn da etwas gegenüber der Verwendung von std::vector, außer dem Schutz vor Größenänderungen ?

    Ein vector<vector<>> ist kein 2D Array, sondern ein Superset davon. (Superset.. Übermenge? Na ja, sollte klar sein was gemeint ist.)
    Ein 2D Array modelliert man also lieber mit einem vector<array<>>. Ein vector<vector<>> ist mehr wie ein Array aus Pointern oder so. Zugegeben, für ihn dürfte das relativ egal sein, aber es ist ja auch nicht besonders viel Aufwand. 😉



  • Ja, ist schon klar.

    Ich frage nur mit dem Gedanken an den BCB5 im Hinterkopf. Ich hab damals damit gearbeitet und würde gefühlmäßig dazu tendieren, erstmal das vorhandene zu verwenden.

    Old School C++ mag ich ja auch nicht, aber das ist definitv ein Old School Compiler. Und der Linker gibt auch gerne mal den Geist auf ...



  • @nn:
    Hm, nein, ich meinte nur, dass es analog zu VegLandscape-Veg noch andere Klassenpärchen gibt. Ich schreibs mal explizit (nur mit den Variablennamen, ohne Methoden) auf:

    class VegLandscape {
    	Veg* veggrid[xsize][ysize];
    }
    

    = wie besprochen.

    class Landscape {
    	CellInformation* cellInfo[xsize][ysize];
    }
    
    class WaterLandscape {
    	Soil* soilgrid[xsize][ysize];
    }
    

    Die Klassen Veg, CellInformation und Soil meinte ich mit "Gridelement-Klassen".
    Diese enthalten ihrerseits Instanzvariablen, und zwar:
    Veg: 3 doubles
    CellInformation: int, double, bitset und 5 Pointer, letztere alle auf unterschiedliche Klassen in einer Klassenhierarchie.
    Soil: 45 Variablen, überwiegend doubles.

    Die 3 Fragen von oben hätt ich dann noch.

    Die Antworten danach guck ich mir jetzt noch mal an.



  • Ich versteh nicht, warum das mit array oder vector noch sein muss, wenn ich auf Pointer verzichte. Vielleicht versteh ich das, wenn ich die ANtworten zu 1)-3) weiß...



  • susie schrieb:

    1. Wann würden die Objekte erzeugt bzw. wo muss ich deren Instanzvariablen belegen? Reicht das im Konstruktor?

    Objekte werden immer sofort erzeugt. Ich weis nicht wie genau du das meinst. Bei einem

    std::vector<int> v(5)
    

    werden sofort 5 int-Objekte erzeugt. Bei einem

    std::vector<int*> v(5)
    

    werden sofort 5 Point-auf-int-Objekte erzeugt. Die ints selbst muss man natürlich noch mal separat erzeugen, wenn man die haben will. Aber grundsätzlich funktioniert das alles immer gleich.

    susie schrieb:

    1. Die meisten Klassen der Objekte (ich nenn es mal Gridelement-Klassen) haben nur doubles oder doubles,floats und bools als Instanzvariablen. Eine Gridelement-Klasse hat aber auch Pointer auf eine Klassenhierarchie als Instanzvariable, die manchmal belegt sind, manchmal nicht (Nullpointer). Geht das dann auch? Denn dann hätt ich ja in der Gridelementklasse auch wieder Pointer drin...

    Äh was?^^

    susie schrieb:

    1. Eine der Gridelement-Klassen hat 45 doubles als Instanzvariable. Wenn ich nun ein Grid mit 100x100 oder gar 500x500 nehme, geht das dann speichertechnisch?
      DAnke nochmal!

    Ne, 500*500*45*8 sind ca 85 MB, das sollte man auf den Heap legen. Daher ja vector<>, der macht das schon gut alleine.



  • cooky451 schrieb:

    susie schrieb:

    1. Die meisten Klassen der Objekte (ich nenn es mal Gridelement-Klassen) haben nur doubles oder doubles,floats und bools als Instanzvariablen. Eine Gridelement-Klasse hat aber auch Pointer auf eine Klassenhierarchie als Instanzvariable, die manchmal belegt sind, manchmal nicht (Nullpointer). Geht das dann auch? Denn dann hätt ich ja in der Gridelementklasse auch wieder Pointer drin...

    Äh was?^^

    Das wäre auch wieder ein Fall für SmartPointer, damit die Objekte, auf die diese Pointer zeigen, auch aufgeräumt werden, wenn die Gridelemente bzw. der vector gelöscht werden.

    Notfalls sonst halt in den Destruktoren der Gridelemente.



  • cooky451 schrieb:

    1. Die meisten Klassen der Objekte ...

    Äh was?^^

    Ja, war da etwas umständlich ausgedrückt. Hier nochmal der vorige BEitrag, wo dasselbe klarer steht:
    http://www.c-plusplus.net/forum/p2272109#2272109

    cooky451 schrieb:

    1. Wann würden die Objekte erzeugt bzw. wo muss ich deren Instanzvariablen belegen? Reicht das im Konstruktor?

    Objekte werden immer sofort erzeugt. Ich weis nicht wie genau du das meinst.

    Ich nehm mal den schwierigsten Fall von grade, jetzt halt nicht mit Pointern:

    class Landscape {
        CellInformation cellInfo[xsize][ysize];
    }
    

    CellInformation enthält aber wie gesagt seinerseits wieder Pointer.
    Wenn ich jetzt ein Objekt der Klasse Landscape erzeuge (mit new), würden in dem Augenblick (per Konstruktor?) Objekte von CellInformation erzeugt? Die Instanzvariablen eines CellInformation-Objekts sind teilweise int, würden dann zufällige Werte drin stehen? Aber schwieriger: manche Instanzvariablen eines CellInformation-Objekts sind Pointer. Was würde da drinstehen? Bisher hieß es immer (in anderem THread hier), wenn ich ein Objekt erzeuge, muss ich sofort alle Instanzvariablen initialisieren und die Pointer auf Null setzen. Soll ich das dann machen oder ist das nicht dasselbe, wie wenn das Grid aus Pointern besteht, die ich auf Null setze?!
    Sorry, falls ich mich kompliziert ausdrücke, bin selbst grad durcheinander und ich weiß nicht besser, wie ich beschreiben kann, was ich meine.



  • susie1 schrieb:

    Sorry, falls ich mich kompliziert ausdrücke,

    Sorry, falls ich mich jetzt kurzfasse, aber das sind alles Sachen, die man sehr schön in einem guten Grundlagenbuch nachlesen kann. Z.B. in Breymanns "Der C++ Programmierer", wo es auch Beispiele zu zwei- und dreidimensionalen Arrays mit Vektoren gibt.


Anmelden zum Antworten