Initialisierliste, mit new erzeugtes Objekt



  • Wenn die Dimension sowieso immer 4 beträgt, könntest du doch eine eigene Klasse schreiben und entsprechende Konstruktoren bereitstellen. Dann wärst du auch zusätzlich flexibel, falls du plötzlich Funktionalität hinzufügen möchtest, und könntest gleichzeitig etwas von den Zeigern abstrahieren. Ist nur so ein Vorschlag... 😉


  • Administrator

    Ganz blöder Vorschlag:

    boost::array<int, 4> const temp = { 0, 1, 2, 3 };
    boost::array<int, 4>* p = new boost::array<int, 4>(temp);
    

    Womöglich ist der Kompiler klug genug, dies wegzuoptimieren 😉

    Grüssli



  • Dravere schrieb:

    Womöglich ist der Kompiler klug genug, dies wegzuoptimieren 😉

    Falls nicht (was ich hier befürchte) hat man viele unnötige Konstruktionen - denk dran, es geht Optimizer nicht um int s. Je nachdem kann sich das beim Quadtree ziemlich negativ auswirken. Abgesehen davon weisst du nicht, ob die Objekte überhaupt kopierfähig sind.



  • Sind sie nicht. Der Vorschlag mit der eigenen Klasse: Ich probier's grad, aber ich glaub das wird scheiße. Ich hatte an sowas gedacht:

    class ChildCollection {
    	public:
    		ChildCollection(const Area& parentArea);
    		boost::array<Quadtree, 4>::iterator begin();
    		boost::array<Quadtree, 4>::iterator end();
    
    	private:
    		boost::array<Quadtree, 4> children;
    	};
    

    Aber ich kann das array natürlich wieder nicht richtig initialisieren. Ich seh's jedenfalls nicht, wie das in der Initialisierliste gehen soll und nen Standardkonstruktor gibts nicht, da es für den Quadtree auch keinen gibt. Es endet also wieder mit Quadtree* als array-Element, dann kann ich mir aber die eigene Klasse sparen.



  • Muss es unbedingt boost::array sein? Dieser Container scheint mir für dein Vorhaben ziemlich ungeeignet.

    Die STL-Container fallen auch weg, weil deine Objekte nicht kopierbar sind (Zeiger und SmartPointer sind wahrscheinlich unnötig/mühsam). Naheliegend wären für mich die Boost.PointerCointainer, z.B. boost::ptr_vector . Oder du schreibst einen eigenen Container, was allerdings nicht mit wenig Aufwand verbunden ist, wenn du auch Iteratoren unterstützen willst.

    Ich bin mir allerdings eh nicht ganz sicher, was du genau tun willst. Sollte ChildCollection -Konstruktor nicht vier Parameter haben? Oder erstellst du die Quadtree -Unterbäume erst im Konstruktor selbst?



  • Ich erstelle sie zwangsläufig erst bei der Konstruktion der ChildCollection, weil sie nicht kopierbar sind. Zeiger wollte ich vermeiden, weil ich sonst wieder einen Destruktor brauche. Klar, das ist alles nicht furchtbar dramatisch, ich frage mich halt was eine wirklich coole Lösung wäre.

    Du hast mich immerhin auf ptr_array gebracht, das hört sich schon mal besser an als alles was ich bisher ausprobiert habe. Kann iterieren, brauche keinen eigenen Destruktor, fast schon geil. Nur die child Quadtrees sind auf dem Heap allokiert. Da komm ich wahrscheinlich nicht drum herum, wenn ich es nicht schaffe, ein Array zu initialisieren. Im Moment ist das meine favorisierte Lösung. 🙂



  • Hm, boost::ptr_array scheint ein recht guter Kompromiss zu sein, war mir bisher selber nicht bekannt. Ich dachte, die Pointer-Container gäbe es nur als Äquivalent zu den STL-Containern. 🙂

    Die QuadTrees sollten auch auf dem Heap allokiert sein. Ich kann mir vorstellen, dass das Ganze grösser werden könnte, und mit dem Heap bist du diesbezüglich viel flexibler. Ich denke hingegen eher nicht, dass der Performancenachteil durch dynamische Allokationen derart dramatisch sein sollte...



  • Natürlich, es sind alles Luxusprobleme, da sind wir uns einig. 🙂 ptr_array ist auf den ersten Blick komisch. Der Zugriff ist trotzdem über Referenzen, jetzt kann ich offenkundig nicht myArray[0] zuweisen, weil dann würde ich den Quadtree zu kopieren versuchen. Beim ptr_vector isses klar, da würde ich ein push_back machen. Naja ich geh jetzt schlafen. Vielleicht mache ich morgen eine vollkommen uncoole und einfache Lösung. 🙂



  • class Foo
    {
        boost::array<boost::optional<Quadtree>, 4> children; // Quadtree muss _nicht_ default konstruierbar sein!
    };
    

    Initialisieren kannst du das dann entweder über copy-construction (einfach zuweisen - intern wird dann der copy-ctor aufgerufen), oder über eine in-place-factory (was die unnötige Kopie vermeiden würde).

    p.S.: boost::optional ist IMO eine sehr interessante, aber oft "übersehene" Library.



  • Hmmm. Also optionals statt pointer, das erlaubt evtl. einen noch günstigeren Zugriff und löst das Destruktor-Problem. Dafür wird die Konstruktion umständlicher und das Objekt ist immer so groß, auch wenn es keine Kindknoten hat. (Letzteres stört mich etwas. Aber ok, kann man sich auch überlegen, thx. EDIT: ne is quatsch, die child-collection gibt's ja nur, wenn der Knoten Kinder hat)

    Ich tendiere jetzt trotzdem eher zum unschönen array<Quadtree*, 4>, außer ich krieg das ptr_array noch zum laufen.


  • Administrator

    @hustbaer,
    Danke für den Hinweis wegen boost::optional, hab das Ding tatsächlich noch nie gesehen 😃

    @Optimizer,

    #include <boost/ptr_container/ptr_array.hpp>
    
    int main()
    {
    	boost::ptr_array<boost::nullable<int>, 4> arr;
    
    	arr.replace<0>(new int(0));
    	arr.replace<1>(new int(1));
    	arr.replace<2>(new int(2));
    	arr.replace<3>(new int(3));
    
    	return 0;
    }
    

    Wenn du die Objekte im ptr_array nicht wieder auf 0 zurücksetzen möchtest, dann kannst du auf boost::nullable verzichten. Ohne boost::nullable darfst du aber nie bei replace eine 0 übergeben, sonst hast eine Exception am Hals.

    Grüssli



  • Danke, ich habe es tatsächlich mit dem replace nicht gecheckt und das IntelliSense checkt auch überhaupt nichts mehr so dass ich es gar nicht gesehen habe. Das nullable ist hässlich, aber das brauche ich zum Glück nicht. Entweder gibt es alle vier Kinder oder keines, deswegen verwende ich jetzt einen auto_ptr<ptr_array<Quadtree, 4>>.

    Damit hab ich jetzt endgültig 2 Indirektionen zu den Kindknoten hin, aber ansonsten ist alles ziemlich geil, zum Beispiel kann ich die Kinder alle entfernen indem ich einfach den auto_ptr resette.


Anmelden zum Antworten