n dimensionale arrays



  • Hallo Leute, hier mein Implementierungsvorschlag für eine n-dimensionale Arrayklasse.

    #ifndef _DEF_AREA_H_
    #define _DEF_AREA_H_
    
    // titus78[at]gmx.net
    
    template<typename T, int d> struct Area {
    	Area(): t(0) { for(int i=0;i<d;i++) { dim[i] = 0; } }
    	Area(int* x) : t(new Area<T,d-1>[x[0]]) {
    		std::memcpy(dim,x,d*sizeof(int));
    		for(int i=0;i<dim[0];i++) {	t[i] = Area<T,d-1>(&dim[1]);	}
    	}
    	Area(const Area& a) : t(new Area<T,d-1>[a.dim[0]]) {
    		std::memcpy(dim,a.dim,d*sizeof(int));
    		for(int i=0;i<a.dim[0];i++) { t[i] = a.t[i]; }
    	}
    	~Area() {	delete [] t;}
    	Area& operator=(const Area<T,d>& a) {
    		if(this == &a) { return *this; }
    		if(dim[0] < a.dim[0]) {	delete [] t; t = new Area<T,d-1>[a.dim[0]]; }
    		std::memcpy(dim,a.dim,d*sizeof(int));
    		for(int i=0; i<dim[0];i++) { t[i] = a.t[i]; }
    		return *this;
    	}
     	Area<T,d-1>& operator[](int i) { return t[i]; }
    	const Area<T,d-1>& operator[](int i) const{ return t[i]; }
    	bool operator==(const Area<T,d>& a) {
    		if(a.dim[0] == dim[0]) {} else { return false; }
    		for(int i=0; i<dim[0];i++) { if(t[i] == a.t[i]) {} else { return false; }	}
    		return true;
    	}
    	Area<T,d-1>* t;
    	int dim[d];
    };
    
    template<typename T> struct Area<T,1> {
    	Area(): t(0), dim(0) { }
    	Area(int* x): t(new T[*x]) { dim = *x; }
    	Area(const Area& a): t(new T[a.dim]), dim(a.dim) {
    		for(int i=0;i<a.dim;i++) { t[i] = a.t[i];	}
    	}
    	~Area() {	delete [] t;}
    	Area& operator=(const Area& a) {
    		if(this == &a) { return *this; }
    		if(dim < a.dim) {	delete [] t; t = new T[a.dim]; }
    		dim = a.dim;
    		for(int i=0; i<dim;i++) { t[i] = a.t[i];	}
    		return *this;
    	}
    	bool operator==(const Area<T,1>& a) {
    		if(a.dim == dim) {} else { return false; }
    		for(int i=0; i<dim;i++) { if(t[i] == a.t[i]) {} else { return false; }	}
    		return true;
    	}
    	T& operator[](int i) { return t[i]; }
    	const T& operator[](int i) const { return t[i]; }
    	T* t;
    	int dim;
    };
    
    #endif
    

    Bin dankbar für Kommentare und Anregungen



  • DAS verstehe ich unter einem Hack - OMG 🙄

    Ich hab den Source jetzt nur überflogen, aber mir scheint, du hast keine Indexprüfung darin. Dann gibt es keinen Grund, dein Array zu benutzen, was kann es, was ein normales Array nicht kann?
    Außerdem würde ich asserts und exceptions einbauen, im Moment sieht das relativ wackelig aus. Um es mal krass auszudrücken - ich traue dir nicht 😉



  • Willst du für mehrdimensionale Arrays jedes Mal "new[]"s schachteln? Dem würde ich noch viel weniger trauen.

    Naja, mal ein paar Ideen (hauptsächlich Stilsachen, die mir so einfallen. Bin zu müde, um nach Bugs zu suchen 🙂 ):

    #defines (oder allgemein Bezeichner) dürfen nicht mit _ + Großbuchstabe anfangen, das ist für die Implementierung reserviert. Der Include-Guard ist also theoretisch ungültig.
    Warum "int d" und nicht "std::size_t d" als template-Parameter etc.? Das ist der Typ für Array-Indizes.
    Warum memcpy und for-Schleifen zum Kopieren von Arrays? -> std::copy, das läuft in guten Implementierungen eh aufs gleiche raus 🙂
    Wie wäre es mit einem STL-Interface?
    operator== sollte const sein, oder gleich ein Nonmember.
    Die Daten gehören private!
    Mit std::equal hätte man den operator== einfacher implementieren können 🙂



  • Die Idee mit der Templaterekursion ist an dieser Stelle nicht schlecht, aber die Umsetzung gefällt mir nicht wirklich. Du solltest dem ganzen lieber irgendwie eine gemeinsame Oberklasse spendieren, da sich der Code ziemlich ähnelt. Ausserdem helfen Kommentare im Sourcecode manchmal.



  • Also bei mir will es mein Compiler nicht übersetzten:

    error C2989: 'Area<T,1>' : Vorlagenklasse wurde bereits als Nicht-Vorlagenklasse definiert
    error C2988: Unerkannte Vorlagendeklaration/-definition



  • operator void schrieb:

    Willst du für mehrdimensionale Arrays jedes Mal "new[]"s schachteln? Dem würde ich noch viel weniger trauen.

    Bezog sich das auf mein Post? Wenn ja, dann musst dir mir jetzt genau erklären, wo man bei asserts, exceptions oder Indexprüfung ein new braucht.



  • Leidest du unter Verfolgungswahn? Das sieht doch ein Blinder auf wen sich das Posting bezog 🙄 .



  • Optimizer schrieb:

    Bezog sich das auf mein Post? Wenn ja, dann musst dir mir jetzt genau erklären, wo man bei asserts, exceptions oder Indexprüfung ein new braucht.

    Ich bezog mich auf:

    Dann gibt es keinen Grund, dein Array zu benutzen, was kann es, was ein normales Array nicht kann?

    Und ein "normales Array" ist in dem Fall für mich ein verschachteltes new[], was unabhängig von assert() ein mächtiger Unterschied zu Area<> ist.



  • Ok, mag sein. Ich verstehe aber trotzdem nicht, was gegen Asserts und Exceptions spricht. Ich denke da an

    array[-7893465] = <wert>;
    


  • Optimizer schrieb:

    Ich hab den Source jetzt nur überflogen, aber mir scheint, du hast keine Indexprüfung darin.
    Außerdem würde ich asserts und exceptions einbauen, im Moment sieht das relativ wackelig aus. Um es mal krass auszudrücken - ich traue dir nicht 😉

    Vollkommen richtig, Indexprüfung, exception safety, private Membervariablen, ... fehlen (noch).

    Optimizer schrieb:

    Dann gibt es keinen Grund, dein Array zu benutzen, was kann es, was ein normales Array nicht kann?

    Hätte vielleicht ein kleines Beispiel mitschicken können :

    #include "area.h"
    #include <iostream>
    #include <cassert>
    
    int main() {
    
    	// create a 4D hypercube with range 2 in each dimension
    	std::size_t dimension[4] = { 2,2,2,2 };
    	Area<int,4> area_4d_1(dimension);
    
    	area_4d_1[0][0][0][0] = 1;
    	area_4d_1[0][0][0][1] = 2;
    	area_4d_1[0][0][1][0] = 3;
    	area_4d_1[0][0][1][1] = 4;
    	area_4d_1[0][1][0][0] = 5;
    	area_4d_1[0][1][0][1] = 6;
    	area_4d_1[0][1][1][0] = 7;
    	area_4d_1[0][1][1][1] = 8;
    	area_4d_1[1][0][0][0] = 9;
    	area_4d_1[1][0][0][1] = 10;
    	area_4d_1[1][0][1][0] = 11;
    	area_4d_1[1][0][1][1] = 12;
    	area_4d_1[1][1][0][0] = 13;
    	area_4d_1[1][1][0][1] = 14;
    	area_4d_1[1][1][1][0] = 15;
    	area_4d_1[1][1][1][1] = 16;
    
    	// extract two 3D cubes
    	Area<int,3> area_3d_1 = area_4d_1[0];
    	Area<int,3> area_3d_2 = area_4d_1[1];
    
    	// extract four 2D tiles
    	Area<int,2> area_2d_1 = area_3d_1[0];
    	Area<int,2> area_2d_2 = area_3d_1[1];
    	Area<int,2> area_2d_3 = area_3d_2[0];
    	Area<int,2> area_2d_4 = area_3d_2[1];
    
    	// extract eight 1D arrays
    	Area<int,1> area_1d_1 = area_2d_1[0];
    	Area<int,1> area_1d_2 = area_2d_1[1];
    	//...
    	Area<int,1> area_1d_7 = area_2d_4[0];
    	Area<int,1> area_1d_8 = area_2d_4[1];
    
    	// print the values
    	std::cout << area_1d_1[0] << std::endl;
    	std::cout << area_1d_1[1] << std::endl;
    	std::cout << area_1d_2[0] << std::endl;
    	std::cout << area_1d_2[1] << std::endl;
    	//...
    	std::cout << area_1d_7[0] << std::endl;
    	std::cout << area_1d_7[1] << std::endl;
    	std::cout << area_1d_8[0] << std::endl;
    	std::cout << area_1d_8[1] << std::endl;
    
    	// create a 1D array
    	std::size_t dimension2[1] = { 3 };
    	Area<int,1> area_1d_9(dimension2);
    	area_1d_9[0] = 1;
    	area_1d_9[1] = 1;
    	area_1d_9[2] = 1;
    
    	// copy it into another
    	Area<int,1> area_1d_10(area_1d_9);
    
    	// test for equality
    	assert(area_1d_10 == area_1d_9);
    
    	// build a 2D area from them and set the rest by hand
    	std::size_t dimension3[2] = { 3, 3};
    	Area<int,2> area_2d_7(dimension3);
    	area_2d_7[0] = area_1d_9;
    	area_2d_7[1] = area_1d_10;
    	area_2d_7[2][0] = 1;
    	area_2d_7[2][1] = 1;
    	area_2d_7[2][2] = 1;
    
    	// ...
    }
    

    operator void schrieb:

    #defines (oder allgemein Bezeichner) dürfen nicht mit _ + Großbuchstabe anfangen, das ist für die Implementierung reserviert. Der Include-Guard ist also theoretisch ungültig.

    bis du sicher, ich meine steht sowas im Standard oder ist es eine Konvention?
    Ansonsten danke für deine Ideen !



  • titus78 schrieb:

    operator void schrieb:

    #defines (oder allgemein Bezeichner) dürfen nicht mit _ + Großbuchstabe anfangen, das ist für die Implementierung reserviert. Der Include-Guard ist also theoretisch ungültig.

    bis du sicher, ich meine steht sowas im Standard oder ist es eine Konvention?
    Ansonsten danke für deine Ideen !

    steht im standard
    weiters sind zwei unterstriche nicht erlaubt
    und bezeichner die mit unterstrich und kleinbuchstabe anfangen sind im globalen 'namensraum' nicht erlaubt...


Anmelden zum Antworten