2 dimensionales Array vs std::vector<std::vector>



  • Hallo,

    ich hoffe der Topictitel zeigt schon worauf ich hinausmöchte.
    Ich möchte ein 2 dimensionales Feld (alles strings) speichern.
    Ich würde ja einfach ein 2-Dimensionales Array nehmen, jedoch ist das Problem die unbekannte Menge der Daten. (Ergebnis einer DB-Abfrage)

    Nun möchte ich - sofern möglich - gerne einen 2 dimensionalen Standardcontainer benutzen, aber ich habe leider nichts gefunden.

    Ich habe mir zwar mit einem Vektor im Vektor beholfen, jedoch gefällt mir diese Lösung ehrlich gesagt gar nicht. Ziemlich unübersichtlich für mich.

    Frage: Gibt es da eine elegantere Lösung in C++? (Gerne auch eine Borland 6 c++ builder spezifische Lösung...)

    Gruß
    R



  • Was ist denn daran unübersichtlich? Vector im Vector ist ne gute Lösung. Schreib dir notfalls ne Klasse, die diesen kapselt, und bau dir Methoden, die den Zugriff vereinfachen. Fertig.



  • Hallo Robin,

    ich denke die boost multi-arrays sind das was Du brauchst.

    Gruß
    Werner



  • std::Robin schrieb:

    ... Ich würde ja einfach ein 2-Dimensionales Array nehmen, jedoch ist das Problem die unbekannte Menge der Daten. (Ergebnis einer DB-Abfrage)
    R

    Um etwas vorzuschlagen muesste ich mehr wissen. Heisst "unbekannte Menge" das nur die erste Dimension des zweidimensionalen Arrays nicht feststeht,
    oder das die zweite Dimension nicht feststeht, oder beide Dimensionen nicht feststehen ?



  • char a[x][y];

    x und y sind unbekannt.
    Realisiert werden soll ein Feld welches ich koordinatenartig ansprechen kann.

    Ich versuche gerade mich in Boost MultiArrays einzulesen, jedoch tue ich mich mit englisch schwer und das dauert wohl noch etwas.
    Einer Quick&Dirty Lösung gegenüber wäre ich auch aufgeschlossen.

    Gruß
    R



  • hmm ..

    char** items = new char*[x];
    for (size_t cur = 0; cur < x; ++cur)
        items[cur] = new char[y];
    
    // nutzen ...
    items[0][3] = 'a';
    
    // freigeben ...
    for (size_t cur = 0; cur < x; ++cur)
        delete [] items[cur];
    
    delete [] items;
    

    bin mir nciht sicher ob ichs sauber freigegeben hab und ist nicht getestet ... so in etwa is es aber quick&dirty ...



  • wieso nicht wie deiN Threadtitel es sagt?

    std::vector<std::vector<char>> a;



  • std::Robin schrieb:

    Einer Quick&Dirty Lösung gegenüber wäre ich auch aufgeschlossen.

    std::Robin schrieb:

    die unbekannte Menge der Daten. (Ergebnis einer DB-Abfrage)

    Wenn das so ist so sollte doch der Record der da abgeholt wird bekannt sein, also wurde doch ein

    std::vector< Record >
    

    reichen. Ein Record hat dann die Struktur

    struct Record
    {
        int m_datum1;
        egal_type m_datum 2;
        // usw.
    };
    

    oder wo kommt die zweite Dimension her?


  • Mod

    gegen vector< vector< T > > ist nicht unbedingt etwas einzuwenden, solange du nur über Koordinaten navigierst. Eine andere Methode verwendet valarray mit slice - aber auch dafür muss man sich erst etwas einlesen. Eine selbstgeschrieben Klasse tut es auch:

    template<typename T, typename A = std::allocator< T > >
    class Array2D
    {
    public:
        typedef A allocator_type;
        typedef typename allocator_type::value_type value_type;
        typedef typename allocator_type::size_type size_type;
        typedef typename allocator_type::difference_type difference_type;
        typedef typename allocator_type::pointer pointer;
        typedef typename allocator_type::const_pointer const_pointer;
        typedef typename allocator_type::reference reference;
        typedef typename allocator_type::const_reference const_reference;
    
        typedef pointer iterator;
        typedef const_pointer const_iterator;
        explicit Array2D(size_type x = 0, size_type y = 0, const_reference value = value_type())
            : x_( x ), y_( y ), p_( A().allocate( x * y ) )
        {
            try
            {
                std::uninitialized_fill( begin(), end(), value );
            }
            catch ( ... )
            {
                A().deallocate( begin(), size() );
                throw;
            }
        }
        Array2D(const Array2D& other)
            : x_( other.x_dim() ), y_( other.y_dim() ), p_( A().allocate( other.size() ) )
        {
            try
            {
                std::uninitialized_copy( other.begin(), other.end(), begin() );
            }
            catch ( ... )
            {
                A().deallocate( begin(), size() );
                throw;
            }
        }
        ~Array2D()
        {
            allocator_type allocator;
            for ( iterator p = end(); p != begin(); )
                allocator.destroy( --p );
            allocator.deallocate( p_, size() );
        }
        Array2D& operator=(const Array2D& rhs)
        {
            Array2D( rhs ).swap( *this );
            return *this;
        }
        void swap(Array2D& other)
        {
            using std::swap;
            swap( x_, other.x_ );
            swap( y_, other.y_ );
            swap( p_, other.p_ );
        }
        size_type x_dim() const { return x_; }
        size_type y_dim() const { return y_; }
        size_type size()  const { return x_dim() * y_dim(); }
        iterator       begin()       { return p_; }
        const_iterator begin() const { return p_; }
        iterator       end()         { return begin() + size(); }
        const_iterator end()   const { return begin() + size(); }
    
        pointer operator[](size_type x) { return p_ + x * y_dim(); }
        const_pointer operator[](size_type x) const { return p_ + x * y_dim(); }
    
        reference operator()(size_type x, size_type y) { return p_[ x * y_dim() + y ]; }
        const_reference operator()(size_type x, size_type y) const { return p_[ x * y_dim() + y ]; }
    private:
        size_type x_;
        size_type y_;
        pointer p_;
    };
    
    template<typename T, typename A>
    void swap(Array2D< T, A >& lhs, Array2D< T, A >& rhs)
    {
        lhs.swap( rhs );
    }
    

    hier fehlt ein bisschen Funktionalität (z.B. resize und assign). Zuviel davon rückt das ganze dann allerdings wieder sehr nahe an existierende Varianten (insbesondere valarray) heran, dann lohnt sich eine eigene Klasse schon wieder nicht. Es hängt eben sehr vom Verwendungszweck ab.


Log in to reply