[] vs. vector<>



  • *lol* @ volkard: das mit dem April glaub ich aber auch 😉

    Weiß trotzdem nicht was ich glauben soll. Entweder ich verwende weiter float** für meine Funktion oder vector < vector<float> >. Was denn nun?!

    Achso, wenn ich nen vector löschen will, dann brauch ich schon delete, oder? War wohl ein ganz schlechter Aprilscherz?! 😉

    Ich glaube, ich hätte meine Frage morgen stellen sollen, heute hat das anscheinend wenig Sinn *grml* 🙄

    Thx, Matze



  • Guest1 schrieb:

    *lol* @ volkard: das mit dem April glaub ich aber auch 😉

    ok, nicht alle. ich meine natürich alles ernst. mich überrascht nur, daß alle anderen mit schlechten vorsachlägen kommen.

    Weiß trotzdem nicht was ich glauben soll. Entweder ich verwende weiter float** für meine Funktion oder vector < vector<float> >. Was denn nun?!

    du nimmst mich nicht erst, oder? schau nach, was slices (einzahl slice) sind. schau nach. schau nach. schau nach. schau nach.

    Achso, wenn ich nen vector löschen will, dann brauch ich schon delete, oder?

    nee. das macht der im destruktor alleine.

    Ich glaube, ich hätte meine Frage morgen stellen sollen, heute hat das anscheinend wenig Sinn *grml* 🙄

    kann heute aber schon mal lesen, was slices sind. es wird dich sicherlich inspirieren.



  • volkard schrieb:

    Guest1 schrieb:

    Wie sieht es aus? Ist ein Einsatz von vector<> generell zu empfehlen und gegen [] zu ersetzen

    auf gar keinen fall generell.
    alle generalisierungen sind falsch.

    Eher nicht, aber in diesem Fall ACK.

    oder sollte man doch die "alten Hausmittel" weiter verwenden? Was ist besser und warum?

    also vector<vector<float> > als ersatz für 2-dimensionale arrays zu benutzen, ist performancetechnischer superoberdoppelriesenmist.

    Das ist eine Generalisierung :p Außerdem stimme ich ihr nicht zu.

    und glaub heute ja keinem was. alle wollen dich nur in den april schicken.

    Glauben kann man schon, was ich geschrieben hab. Ich hab halt bloß die negativen Sachen weggelassen 😉

    Guest1: Wenn du nur die Funktionalitäten brauchst, die ein Array hat, dann nimm auch eins. Wenn irgendwas von den oben genannten Sachen gebrauchen kannst, solltest du Vorteile und Nachteile von nem vector feinsäuberlich abwägen.



  • oder sollte man doch die "alten Hausmittel" weiter verwenden? Was ist besser und warum?

    also vector<vector<float> > als ersatz für 2-dimensionale arrays zu benutzen, ist performancetechnischer superoberdoppelriesenmist.

    Das ist eine Generalisierung :p [/quote]
    ok, ist eine.

    Michael E. schrieb:

    volkard schrieb:

    auf gar keinen fall generell.
    alle generalisierungen sind falsch.

    Eher nicht, aber in diesem Fall ACK.

    aber das war erst recht eine.

    Außerdem stimme ich ihr nicht zu.

    ok. aber

    float **transpose(float **array){
    

    ist ne andere geschichte. hier geht es wohl um eher kleine arrays mit mickrigen elementen, die voll bestückt sind. also wenn du für eine 10*10-matrize gerne 11 mal die kosten für einen operator new zahlst, ist das dein problem. aber ich petze da gerne und erzähle, daß es unheimlich lahm ist.

    Glauben kann man schon, was ich geschrieben hab. Ich hab halt bloß die negativen Sachen weggelassen 😉

    naja, hast ein bißchen arg weggelassen.



  • volkard schrieb:

    Michael E. schrieb:

    volkard schrieb:

    auf gar keinen fall generell.
    alle generalisierungen sind falsch.

    Eher nicht, aber in diesem Fall ACK.

    aber das war erst recht eine.

    Hast du mich falsch verstanden? Ich hab gemeint, dass man auf die gestellte Frage keine generelle Antwort geben kann, aber Generalisierungen allgemein nicht zwangsläufig falsch sein müssen. Da war jetzt keine Generalisierung drin.

    Außerdem stimme ich ihr nicht zu.

    ok. aber

    float **transpose(float **array){
    

    ist ne andere geschichte.

    ACK. Hier sollte man (soweit mans bisher beurteilen kann) Arrays benutzen.

    also wenn du für eine 10*10-matrize gerne 11 mal die kosten für einen operator new zahlst, ist das dein problem.

    Kommt ganz auf den Fall an. Aber hier würd ich das wie gesagt nicht machen.

    Glauben kann man schon, was ich geschrieben hab. Ich hab halt bloß die negativen Sachen weggelassen 😉

    naja, hast ein bißchen arg weggelassen.

    *indieeckestell*



  • Michael E. schrieb:

    float **transpose(float **array){
    

    ist ne andere geschichte.

    ACK. Hier sollte man (soweit mans bisher beurteilen kann) Arrays benutzen.

    ne, ein vector geht auch hier:

    //10*10 vector erstellen
    std::vector<float> v(100);
    //auf element 3,5 zugreifen
    v[3*10+5]=15.3f;
    

    aber wahrscheinlich will volkard auf valarray/slice_array hinaus, oder irr ich mich da?



  • alle generalisierungen sind falsch

    lol ziemlich paradox oder? 😉



  • otze schrieb:

    Michael E. schrieb:

    float **transpose(float **array){
    

    ist ne andere geschichte.

    ACK. Hier sollte man (soweit mans bisher beurteilen kann) Arrays benutzen.

    ne, ein vector geht auch hier:

    //10*10 vector erstellen
    std::vector<float> v(100);
    //auf element 3,5 zugreifen
    v[3*10+5]=15.3f;
    

    aber wahrscheinlich will volkard auf valarray/slice_array hinaus, oder irr ich mich da?

    Natürlich *geht* es auch. Es geht aber ums Beste.



  • volkard schrieb:

    Weiß trotzdem nicht was ich glauben soll. Entweder ich verwende weiter float** für meine Funktion oder vector < vector<float> >. Was denn nun?!

    du nimmst mich nicht erst, oder? schau nach, was slices (einzahl slice) sind. schau nach. schau nach. schau nach. schau nach.

    Klar nehm ich dich ernst. Hab ja nie was anderes behauptet :p

    Also ok: hab mir die Slices mal im "Stroustrup" angeschaut und es scheint so, als ob man mit ihnen und mit nem valarray einen schönen effektiven Datentypen bauen kann, auf den man genauso zugreifen kann wie auf ein mehrdim. Array.

    Auch wenn ich noch nicht alles davon verstanden habe, scheint das Konzept doch recht effektiv zu sein. Gleich mal an die Umsetzung machen, ich bedanke mich erstmal bis hierhin, dass ihr einem armen C-Programmierer ein wenig C++ Nachhile gegeben habt 😉

    Danke, Matze



  • Guest1 schrieb:

    Also ok: hab mir die Slices mal im "Stroustrup" angeschaut und es scheint so, als ob man mit ihnen und mit nem valarray einen schönen effektiven Datentypen bauen kann, auf den man genauso zugreifen kann wie auf ein mehrdim. Array.

    netterweise steht ne fertige Matrix-Klasse da.

    man könnte ich noch überlegen, eine TempTransMatrix-Klasse zu bauen, die keinen eigenen speicher besitzt, sondern nur eine referenz auf ein val_array einer länger bestehenden Matrix und die slices anders definiert, so daß man beim elementzugriff gleich das gefühl hat, als sei die matrix transponiert, aber in wirklichkeit hat man gar nix transponiert. sozusagen ne virtuelle transponierte. könnte speed bringen, wenn man öfters nur transpose für zwischenergebnisse braucht. man könnt's aber auch sein lassen, weil das noch viel zu schwierig ist.



  • volkard schrieb:

    netterweise steht ne fertige Matrix-Klasse da.

    Du meinst in dem Buch?
    Ja dort schon, da brauch man eigentlich nur abschreiben 😉
    Aber das "Verstehen" des Codes ist wichtiger...

    Das mit dem transpose() war nur ein Beispiel, was zwar auch implementiert ist, aber nur einen mickrigen Bestandteil darstellt. Daher sollte dort nicht der Fokus drauf liegen...

    Danke für alles,
    Matze



  • volkard schrieb:

    netterweise steht ne fertige Matrix-Klasse da.

    Du meinst in dem Buch?
    Ja dort schon, da brauch man eigentlich nur abschreiben 😉
    Aber das "Verstehen" des Codes ist wichtiger...

    Das mit dem transpose() war nur ein Beispiel, was zwar auch implementiert ist, aber nur einen mickrigen Bestandteil darstellt. Daher sollte dort nicht der Fokus drauf liegen...

    Danke für alles,
    Matze



  • Oh oh, dass mit valarrays und slices war keine gute Idee 😞
    Ich habe mein Programm, welches ein Neuronales Netz anlernt von float** auf die Klassen mit valarrays und slices 1:1 umgeschrieben und das Ergebnis ist grauenhaft:

    Beim selben Lernprozess des Netzes benötigt die neue Version 300% der Zeit von der alten - soviel zum Thema "ich benutze mal kein float** mehr". Werd ich mir wohl schnell wieder aus dem Kopf schlagen :|



  • Guest1 schrieb:

    Oh oh, dass mit valarrays und slices war keine gute Idee 😞
    Ich habe mein Programm, welches ein Neuronales Netz anlernt von float** auf die Klassen mit valarrays und slices 1:1 umgeschrieben und das Ergebnis ist grauenhaft:
    Beim selben Lernprozess des Netzes benötigt die neue Version 300% der Zeit von der alten - soviel zum Thema "ich benutze mal kein float** mehr". Werd ich mir wohl schnell wieder aus dem Kopf schlagen :|

    und? war der code am ende schöner zu lesen? war es einfacher, nicht immer an new oder delete denken zu müssen? haste was über c++ gelernt und war das im moment wichtiger, als ein bißchen speed? vermutlich schon.

    ich gehe davon aus, daß du eine feine Matrix-Klasse gebaut hast. und daß du den code von struppi auch kapiert hast. und daß das vorher viel zu kompliziert gewesen wäre, mir dir weiter über nette techniken zu quatschen. und da gibt es noch schrecklich viel zu erzählen.

    so, von deiner Matrix-klasse zu sowas wie

    //ungetestet
    size_t roundedDownLog2(size_t x){
    	int r=0;
    	while(x/=2)
    		++r;
    	return r;
    }
    size_t roundedUpLog2(size_t x){
    	return roundedDownLog2(x-1)+1;
    }
    
    template<typename T>
    class Array{
    private:
    	T* data;
    	Array(Array const&);
    	Array& operator=(Array const&);
    public:
    	Array(size_t size){
    		data=new T[size];
    	}
    	~Array(){
    		delete[] data;
    	}
    	T& operator[](size_t index){
    		return data[index];
    	}
    };
    
    template<typename T>
    class FastArray2d{
    private:
    	size_t shift;
    	Array<T> data;
    public:
    	FastArray2d(size_t sizey,size_t sizex):
    		shift(roundedUpLog2(sizex)),
    		data(sizey<<shift){
    	}
    	struct Proxy{
    		FastArray2d* array;
    		size_t y;
    		Proxy(FastArray2d* _array,size_t _y):
    		array(_array),
    		y(_y){
    		}
    		T& operator[](size_t x){
    			return array->at(x,y);
    		}
    	};
    	Proxy operator[](size_t y){
    		return Proxy(this,y);
    	}
    	T& at(size_t y,size_t x){
    		return data[(y<<shift)+x];
    	}
    };
    

    ist es doch nur noch ein katzensprung.

    setz die mal ein. und wenn die auch lahmer ist als rohe float**, dann packen wir einfach mal die float** in die Matrix-klasse und besorgen uns damit wenigstens das schöne automatische delete und müssen nicht mehr immer ** schreiben.

    sag mal die zeiten von FastArray2d, das hab ich nämlich noch nie gemessen, es "fühlt" sich nur schnell an.



  • Sorry volkard, aber als "Katzensprung" würde ich das nicht bezeichnen :|
    (Mit der folgenden Frage krieg ich bestimmt wieder Haue...)

    @volkard: Nun habe ich noch ein Problem: wenn ich deine Klasse nehme und z.B. folgende Klassenmethode (abgekürzt) habe:

    void f(const FastArray2d<float>& feld){
        anderes_feld[0][0] = feld[0][0];
    }
    

    ... dann kommt folgender Compiler-Fehler:

    feld.cpp: passing `const FastArray2d<float>' as `this' argument of `FastArray2d<T>::Proxy FastArray2d<T>::operator[](unsigned int) [with T = float]

    Dabei sei anderes_feld ein Attribut der Klasse, ebenfalls als FastArray2d<float> realisiert.

    Vielleicht ist's ja ein einfacher Fehler, aber ich kann damit nichts anfangen - habe zwar schon versucht herauszufinden was denn das Problem ist, komme aber selbst nach langem Überlegen nicht drauf 😞
    Macht der mit der Referenz Probleme? Wäre für mich das Naheliegendste, aber wie kann man das dann als Referenz realisieren?

    Danke für alles, Matze



  • Guest1 schrieb:

    Vielleicht ist's ja ein einfacher Fehler, aber ich kann damit nichts anfangen - habe zwar schon versucht herauszufinden was denn das Problem ist, komme aber selbst nach langem Überlegen nicht drauf 😞

    das liegt am const.

    meine klasse ist noch gar nicht fertig.
    und zwar muß eine funktion als const deklariert werden, wenn sie auf const-objekte aufrufbar sein soll. das const-deklarieren der funktion verspricht, daß man das objekt nicht ändern kann.
    ich mach zuerst nur Array korrekt, damit die hopser überschaubar bleiben.

    template<typename T>
    class Array{
    private:
        T* data;
        Array(Array const&);
        Array& operator=(Array const&);
    public:
        Array(size_t size){
            data=new T[size];
        }
        ~Array(){
            delete[] data;
        }
        T& operator[](size_t index) const{
            return data[index];
        }
    };
    

    so, jetzt kann man ein const Array benutzen und damoit den op[] aufrufen.
    aber moment mal, das ist ja unfug. dann bringt return data[index]; auch nur ne referenz auf const T und da müßte es nen compilerfehler geben.
    und der anwender darf ja auch nicht

    const Array<int> a(10);
    a[5]=7;
    

    schreiben.

    ich mach die rückgabe auch mal const.

    template<typename T>
    class Array{
    private:
        T* data;
        Array(Array const&);
        Array& operator=(Array const&);
    public:
        Array(size_t size){
            data=new T[size];
        }
        ~Array(){
            delete[] data;
        }
        T const& operator[](size_t index) const{
            return data[index];
        }
    };
    

    so, jetzt geht's.

    const Array<int> a(10);
    a[5]=7;//fehler
    cout<<a[5];//ok
    

    aber toll wäre es, wenn die alte funktionalität auch da wäre. und das geht sogar. man bietet einfach beide versionen des op[] an.

    template<typename T>
    class Array{
    private:
        T* data;
        Array(Array const&);
        Array& operator=(Array const&);
    public:
        Array(size_t size){
            data=new T[size];
        }
        ~Array(){
            delete[] data;
        }
        T const& operator[](size_t index) const{
            return data[index];
        }
        T& operator[](size_t index){
            return data[index];
        }
    };
    

    jetzt liefert der op[] entweder T& oder T const&, je nachdem, ob man ein Array oder const Array verwendet hat.

    und den rest stelle ich mir so vor:

    template<typename T>
    class FastArray2d{
    private:
        size_t shift;
        Array<T> data;
    public:
        FastArray2d(size_t sizey,size_t sizex):
            shift(roundedUpLog2(sizex)),
            data(sizey<<shift){
        }
        struct ProxyConst{
            FastArray2d const* array;
            size_t y;
            ProxyConst(FastArray2d const* _array,size_t _y):
            array(_array),
            y(_y){
            }
            T const& operator[](size_t x){
                return array->at(x,y);
            }
        };
        ProxyConst operator[] const(size_t y){
            return ProxyConst(this,y);
        }
        T const& at const(size_t y,size_t x){
            return data[(y<<shift)+x];
        }
        struct Proxy{
            FastArray2d* array;
            size_t y;
            Proxy(FastArray2d* _array,size_t _y):
            array(_array),
            y(_y){
            }
            T& operator[](size_t x){
                return array->at(x,y);
            }
        };
        Proxy operator[](size_t y){
            return Proxy(this,y);
        }
        T& at(size_t y,size_t x){
            return data[(y<<shift)+x];
        }
    };
    

    ist aber ganz ungetestet. wenn was nicht geht, und der fehler sich dir nicht zeigt, frag wieder, dann hab ich mich bestimmt vertippt.



  • Ok, die Klasse funzt, vielen vielen Dank...
    Du hattest bloß bei den const-Methoden für operator[] und at() das const vor statt nach dem Funktionsnamen geschrieben, ansonsten war alles ok. Achja: der Compiler meckert beim Copy-Konstruktor für Array, dass er private ist. Hab erstmal auskommentiert, dürfte in diesem Kontext nichts machen.

    Trotzdem scheint die Klasse noch langsam zu sein. Schreibe ich nativ mit zwei Zeigern auf float, dann ist's halt unschlagbar schnell. Das Problem ist: auch wenn ich das Ganze gern objektorientiert machen wöllte kommt es eigentlich primär auf Geschwindigkeit an - daher ist es am Ende vielleicht doch das Beste float** zu lassen, auch wenn es nicht sehr schönen Code ergibt.

    Ich würde es ja gern anders machen nur wenn's dann halt viel langsamer ist nützt die ganze schöne Implementierung nichts...



  • Guest1 schrieb:

    Trotzdem scheint die Klasse noch langsam zu sein.

    um wieviel langsamer genau?

    und hast du auch bestimmt die optimierungen im compiler angemacht?

    Schreibe ich nativ mit zwei Zeigern auf float, dann ist's halt unschlagbar schnell.

    ich kenne den rest des programms nicht. ich weiß nicht, wie die zugriffe verteilt sind. unschalgbar ist sehr selten.

    Das Problem ist: auch wenn ich das Ganze gern objektorientiert machen wöllte kommt es eigentlich primär auf Geschwindigkeit an

    das ist in c++ kein problem. man kann total abstrahieren und zahlt null kosten dafür. ich bevorzuge speed auch, und zwar so schlimm, daß ich auch mal vier wochen meiner freizeit opfere, nur um eine schnelle datenstruktur zu schreiben.

    - daher ist es am Ende vielleicht doch das Beste float** zu lassen, auch wenn es nicht sehr schönen Code ergibt.

    kann nicht sein.

    Ich würde es ja gern anders machen nur wenn's dann halt viel langsamer ist nützt die ganze schöne Implementierung nichts...

    es wird zeit, daß ich deinen code sehe.

    wo wir gerade so fein dran sindm erinnere ich nochmal an
    [quote=volkard]und wenn die auch lahmer ist als rohe float**, dann packen wir einfach mal die float** in die Matrix-klasse und besorgen uns damit wenigstens das schöne automatische delete und müssen nicht mehr immer ** schreiben. [/quote]
    und schreibe

    template<typename T>
    class FastArray2d{
    private:
        T** data;
    	size_t sizey;
    	FastArray(FastArray const&);
    	FastArray operator=(FastArray const&);
    public:
        FastArray2d(size_t sizey,size_t sizex):
    		sizey(_sizey){
    		for(size_t y=0;y<sizey;++y)
    			data[y]=new T[x];
        }
    	~FastArray2d(){
    		for(size_t y=0;y<sizey;++y)
    			data[y]=new T[x];
    	}
    	//Proxys unverändert
        T& at(size_t y,size_t x){
            return data[y][x];
        }
        T const& at(size_t y,size_t x) const{
            return data[y][x];
        }
    };
    

    du jetzt die möglichkeit, alle varianten, die dir so einfallen, auszuprobieren. und so ein einfacher wrapper um float** kostet auch null performance, weil alles inline ist und der compiler das alles wegoptimiert, so daß am ende nur ein float** übrigbleibt.



  • Sieht mir nach nem Copy&Paste-Fehler im Destruktor aus, oder? 😉
    Ich werde das mit der Klasse über float** trotzdem mal probieren, dass soviel Speed verloren geht kann da eigentlich nicht sein...
    Ich probier's erstmal aus, mal schauen wenn ich fertig bin.

    Bis dann und danke nochmals, Matze



  • @volkard: die Geschwindigkeit mit Hilfe deiner Klasse (mit Array<T>) im Gegensatz zu vorher ist immernoch um 300% langsamer als wenn man gleich als Klassenattribut im Neuronalen Netz float** nimmt. Der Hauptgrund dürfte wohl auch sein dass ich eine Instanz der 2D-Matrix-Klasse als Zeiger definieren muss, weil es als Klassenattribut nicht geht. Grund dafür sind die Dimensionen des Neuronalen Netzes, welche den Konstruktoren nicht immer als Parameter übergeben werden können, sondern z.B. in den Konstruktoren erst gelesen werden (z.B. von Datei).

    Stimmst du mir zu, dass darin das Problem begründet ist? Schließlich muss ich ja auch bei jedem Zugriff auf ein Matrixelement eine Dereferenzierung machen, z.B. mit "(*matrix)[i][j]"...

    float** in ne eigene Klasse zu packen habe ich noch nicht ausprobiert, es dürfte aber nicht viel bringen IMHO.

    Btw: du hattest oben bei der Implementierung von FastArray2d einen kleinen Fehler drin. Beim Aufruf von at() in Proxy hast du die Parameter x und y vertauscht. Ist mir nur beim näheren Hingucken und nach ein paar unschönen Abstürzen aufgefallen 😉


Anmelden zum Antworten