Matrix mittels Pointer deklarieren


  • Mod

    Werner Salomon schrieb:

    camper schrieb:

    achso, du meintest deinen konstruktor

    natürlich, zu diesen Zeitpunkt war kein anderer da.

    das 2. codeschnipsel in meinem ersten beitrag.

    camper schrieb:

    zweckmässiger ist ein zusätzlicher parameter und direkte initialisierung (wenn du willst, kannst du auch noch einen haufen template-konstruktoren angeben, die dann alle möglichen parameter aufnehemn, falls T nicht copy-konstruiert werden sollen

    den Normalfall haben wir schon.
    eine template-version könnte so aussehen:

    template<typename I1>
             Matrix( size_type nRow, size_type nCol, const I1& i1)
            : m_size( nRow * nCol )
            , m_nCol( nCol )
            , m_ptr( new value_type[ m_size ]( i1 ) )
            { }
    

    das ganze kannst du noch für 2,3,4,5 usw. parameter machen. möglicherweise auch noch noch overloads mit T& - das wird dann allerdings eine ganze menge ;).



  • camper schrieb:

    zweckmässiger ist ein zusätzlicher parameter und direkte initialisierung

    template<typename I1>
             Matrix( size_type nRow, size_type nCol, const I1& i1)
            : m_size( nRow * nCol )
            , m_nCol( nCol )
            , m_ptr( new value_type[ m_size ]( i1 ) )
            { }
    

    Hallo camper,
    das übersetzt weder auf MC VC6,7,8 GNU3.2 oder Comeau.
    Comeau: error: a new-initializer may not be specified for an array
    GNU: error: ISO C++ forbids initialization in array new

    überlassen wir doch einfach das Problem mit dem Anlegen und Initialisieren der Elemente der STL. Wir nehmen einfach einen std::vector und setzen voraus, dass hier die Elemente fortlaufend im Speicher liegen. Das steht zwar nicht im Standard, aber wahrscheinlich im nächsten.

    #include <vector>
    
    template< typename T >
    class Matrix
    {
    public:
        typedef std::vector< T > container_type;
        typedef T value_type;
        typedef typename container_type::size_type size_type;
    
        // 'nRow' ist die Anzahl (number) der Zeilen (row); 'nCol' die der Spalten (column)
        Matrix( size_type nRow, size_type nCol, const value_type& x = value_type() )
            : m_nCol( nCol )                // Anzahl der Spalten für operator[] merken
            , m_coll( nRow * nCol, x )
        {}
    
        Matrix()
            : m_nCol( 0 )
            , m_coll()
        {}
    
        // der operator[] liefert den Pointer auf das erste Element der Zeile(row) 'iRow'
        // diese Methode ermöglicht den Zugriff mit 
        //      Matrix< Type > mx( nRow, nCol );
        //      mx[iRow][iCol] = ... ;
        value_type* operator[]( int iRow )
        {
            return &m_coll[ iRow * m_nCol ];
        }
        const value_type* operator[]( int iRow ) const
        {
            return &m_coll[ iRow * m_nCol ];
        }
    
    private:
        size_type   m_nCol; // Anzahl der Spalten der Matrix
        container_type m_coll;  // Speicher für die Elemente
    };
    

    Damit wird Matrix jetzt sogar kopierbar und default-constructable. Findet jetzt noch jemand einen Fehler ..

    Gruß
    Werner


  • Mod

    ja stimmt, mit arrays kann man keine new-initialisierer liste verwenden.
    bleibt noch die variante mit uninitialized fill:

    boost::scoped_array< char > m_ptr;
    
    Matrix( size_type nRow, size_type nCol, const value_type& x = value_type() )
            : m_size( nRow * nCol )
            , m_nCol( nCol )                // Anzahl der Spalten für operator[] merken
            , m_ptr( new char[ m_size * sizeof x ] )     // Memory für Elemente allokieren
        {
            std::uninitialized_fill_n( reinterpret_cast< value_type* >( m_ptr.get() ), m_size, x );
        }
    

    hier muss man wieder selbst für copy-ctor usw. sorgen.
    für richtiges alignment sorgt zum glück 5.3.4 Abschnitt 10.



  • noch eine frage dazu...

    ist es auch möglich so eine art von matrix, von einer funktion an die nächste zu übergeben, bzw. sie auch als rückgabewert zu setzen?

    wenn ja wie?

    mfg, TFTS

    PS: achso und welcher dieser ganzen codeschnipsel ist jetz die optimale Matrix? 😕



  • TFTomSun schrieb:

    noch eine frage dazu...

    ist es auch möglich so eine art von matrix, von einer funktion an die nächste zu übergeben, bzw. sie auch als rückgabewert zu setzen?

    Definiere Übergeben. Per Referenz oder per Value? Allgemein kann eine beliebige Klasse per Referenz übergeben werden. Die Übergabe per Wert hängt davon ab, wie die entsprechende Klasse ihre Kopier-Semantik handhabt. Die Klasse von Werner kann beides.

    wenn ja wie?

    Beispiel: Übergabe:

    void func(const Matrix<int>& m); // per const-Referenz...
    void gunc(Matrix<int> m); // per Wert..
    

    Beispiel: Rückgabe:

    Matrix<int> func(...) // per Wert...
    Matrix<int>& func(...) // per Referenz... (wobei du hier keine lokalen Objekte vom Typ Matrix zurückgeben solltest...)
    

    PS: achso und welcher dieser ganzen codeschnipsel ist jetz die optimale Matrix?

    Die letzte gepostete Version von Werner ist ganz nett :).

    Btw: Schau dir am besten mal das allgemeine Konzept einer Klasse an, insbesondere wovon es abhängt, ob und wie Kopiervorgänge etc. gehandhabt werden.

    Gruß Caipi



  • die rückgabe funktioniert leider nicht...

    h:\eigene arbeiten\projektarbeit\cprojekte\jpg2bmp\calculate.h(32) : error C2143: syntax error : missing ';' before '<'

    an der stelle wo ich die funktion definiere

    Matrix<double> BGRToDoubleMatrix(BYTE *pBGRData,int nWidth, int nHeight, int nBitPerPixel, int nElement);
    

    jemand ne idee?

    mfg, TFTS



  • ah hat sich erledigt ... ich musste die matrix.h im header meiner calculate klasse includen ... hatte sie vorher nur in der cpp stehen

    mfg, TFTS



  • hallo,

    hab nochmal eine frage dazu ... ich kann leider nie im debug modus sehen welchen wert gerade meine matrix mx[x][y] hat... kann man das problem irgendwie umgehen?

    noch etwas...
    wenn ich mir solche matrizen als membervariablen definiere ... kann ich auch später festlegen wie groß die matrizen sein sollen? bzw. kann ich im nachhinein die größe einer matrix ändern?

    hab noch eine frage ... wie muss ich meine matrix als return value schreiben damit ich sie per const matrix<int>& zürückgeben kann ... ich möchte im prinzip so eine art pointer auf den ausschnitt einer matrix als eine neue matrix zurückgeben ... ohne die werte von der alten matrix in die neue zu kopieren ... geht das?

    mfg, TFTS



  • TFTomSun schrieb:

    hab nochmal eine frage dazu ... ich kann leider nie im debug modus sehen welchen wert gerade meine matrix mx[x][y] hat... kann man das problem irgendwie umgehen?

    Hallo TFTomSun,

    Das kommt auf Deinen Debugger an. Bei meinem kann man zum Beispiel folgendes eingeben - angenommen die Matrix-Variable ist 'm' und ich möchte den Inhalt von m[3][7] sehen

    m.m_coll._Myfirst + 3 * m.m_nCol + 7
    

    bzw.

    *(m.m_coll._Myfirst + 3 * m.m_nCol + 7)
    

    '_Myfirst' ist dabei der Name des Zeigers auf den vector-Anfang in meiner std::vector Pointer-Implementierung. Den musst Du natürlich gegen den Namen in Deiner std::vector-Implementierung austauschen.

    Eine komfortablere Möglichkeit wäre eine kleine Hilfsmethode

    private:
        T data( int iRow, int iCol )
        {
            return (*this)[iRow][iCol];
        }
    

    muss man noch wissen, dass man diese Methode auch im Code einmal aufrufen muss, also z.B. im Konstruktor von Matrix

    template< typename T >
    class Matrix
    {
    public: // usw.
        Matrix( size_type nRow, size_type nCol, const value_type& x = value_type() )
            : m_nCol( nCol )                // Anzahl der Spalten für operator[] merken
            , m_coll( nRow * nCol, x )
        {
            data( 0, 0 ); // <-- Aufruf, damit der Compiler die Methode auch instanziiert !
        }
    

    sonst läßt der Compiler sie evt. weg, weil es sich ja um ein Template handelt und sie nirgendwo benötigt wird.
    Und dann im Debugger (bei Watch) einfach eingeben

    m.data(3,7)
    

    .. vorausgesetzt der kann das !?

    TFTomSun schrieb:

    noch etwas...
    wenn ich mir solche matrizen als membervariablen definiere ... kann ich auch später festlegen wie groß die matrizen sein sollen? bzw. kann ich im nachhinein die größe einer matrix ändern?

    Member ist kein Problem - Größe ändern geht z.B. durch Überschreiben

    Matrix< int > m(3,4);
        // ..
        m = Matrix< int >( 12, 100 ); // jetzt ist 'm' größer
    

    natürlich sind dann auch alle alten Werte weg. Wenn Du die behalten willst, solltest Du Dir eine resize-Methode bauen. Das ist aber ein bißchen tricky, da Elemente innerhalb von 'm_coll' hin- und her-kopiert werden müssen, wenn sich die Anzahl der Spalten ändert.

    TFTomSun schrieb:

    hab noch eine frage ... wie muss ich meine matrix als return value schreiben damit ich sie per const matrix<int>& zürückgeben kann ...

    Vorsicht - Du darfst grundsätzlich keine lokalen Variablen per Referenz oder const Referenz zurückgeben. So was wie

    [const] Matrix< int >& func1()
        {
            Matrix< int > m(..);
            return m;           // <-- GROBER FEHLER - gebe NIE eine lokale Variable per Referenz zurück
        }
    

    ist immer falsch. Wenn Matrix ein Member einer anderen Klasse bzw. Struct ist, so kannst Du darauf eine const Referenz zurückgeben - so wie gewohnt

    class Foo
    {
    public:
        const Matrix< int >& herDamit() const;
    private:
        Matrix< int > m_mx;
    };
    const Matrix< int >& Foo::herDamit() const
    {
        return m_mx;
    }
    

    TFTomSun schrieb:

    ich möchte im prinzip so eine art pointer auf den ausschnitt einer matrix als eine neue matrix zurückgeben ... ohne die werte von der alten matrix in die neue zu kopieren ... geht das?

    Das wird schon schwieriger. Zunächst heißt das ja auch, dass zwei Matrix-Objekte sich einen vector 'm_coll' teilen müßten. Da müßte man noch einiges für tun. Schau Dir vielleicht doch mal die Hilfe zu std::valarray und std::slice usw. an.

    Gruß
    Werner


Anmelden zum Antworten