Schwierigkeiten mit Klasse und dynamischen Array

Also ich glaub ich habs jetzt fertig:

C++:
using namespace std;
#include<iostream>
#include<list>

class DynArray {
	
private:
	list<int*> array;	
	int Index;
	int* arr; 
	int *save;
	
public:

	DynArray () : Index(0) { // Konstruktor
		arr = new int [20];
	}
	
	~DynArray() { //Destruktor
		delete arr;
	}
	
	int& operator[](int str) {
			return arr[str];
	}
	
	void operator= (int wert) {
		if (Index == 20) { // Überprüft ob das Array voll ist
			save = new int [20];
			for (int i = 0; i < 20; i++)  { // Kopiert die Werte aus arr in das Array save
				save[i] = arr[i];
			}
			array.push_back(save); //  Das Array wird in die Liste kopiert und angehängt
			Index = 0; // Index wieder auf 0 setzten
			arr[Index] = wert;  // Array neu mit Werten füllen
		}
		else  {
			arr[Index] = wert; // Falls der Array noch nicht voll ist wird das Array weiter gefüllt 
		}
		Index++;  // Index erhöhen
	}
	
	friend ostream& operator<< (ostream& o, DynArray const& x); // Ausgabeoperator a
};


ostream& operator<< (ostream& o, DynArray const& x) { // Augabeoperator b
	for (int i = 0; i < x.Index; i++)
		o << x.arr[i] << endl;
}

Die Klasse erfüllt die Aufgabenstellungen...

Und man muss noch beachten, dass man save dynamisch anlegen muss, da das Array save nach der if Schleife zerstört werden würde...

lg Meiki

p.s.: Danke für die Hilfe!
 
Ich habe es mal eben versucht zu implementieren, leider weis ich bei der ausgabe gerade nicht weiter. Vielleicht findet sich ja noch wer der das Problem kennt.
Da du leider keine Fehlermeldung mit angegeben hast (und ich grade keine Möglichkeit zum Testen habe), kann ich nur eine Vermutung äußern: hast du es schon mal mit einem const_iterator probiert?

Also ich glaub ich habs jetzt fertig:
Warum hast du jetzt wieder operator = überladen? Was willst du damit bezwecken? Auch ist mir das allgemeine Verhalten der Klasse nicht ganz klar. Sobald ich das 21. Element eingefügt habe, kann ich plötzlich nicht mehr auf die ersten 20 Elemente zugreifen? Und noch dazu befindet sich das 21. Element dann an Position 0 statt 20… abgesehen davon besitzt die Klasse immer noch ein Speicherleck, da es zu dem new int [20] in Zeile 29 nirgends ein delete [] gibt.

Und man muss noch beachten, dass man save dynamisch anlegen muss, da das Array save nach der if Schleife zerstört werden
Was ist eine if-Schleife?

Grüße, Matthias

PS: Was mir grade noch aufgefallen ist: im Destruktor muss es delete[] heißen, nicht delete.
 
Zuletzt bearbeitet:
@Matthias Danke genau das war das Problem ich frage mich nur warum, ich verstehe nicht warum ich diesmal einen const_iterator benötige. Wenn ich mit Listen gearbeitet habe reichte immer ein normaler Iterator.

@topic Wegen dem Zugriff muss man sich noch die Logik überlegen ist nicht ganz trivial :(

C++:
#include "test.h"

DynArray::DynArray()
: index(0), size(0)
{
   arr = new int[20];  // Speicher reservieren bei der Initialisierung
}

DynArray::~DynArray()
{
    if (!liste.empty())
    {
        std::list<int*>::const_iterator it;
        for (it = liste.begin(); it != liste.end(); ++it)
        {
            delete[] *it;
        }
    }
    delete[] arr; // Am Ende des Programms wird der Speicher freigegeben
}

int& DynArray::operator[](int str)
{
    if (str < size)
    {
        // Logik für Zugriff auf die richtige Stelle
    }
    else
    {
        // Exception werfen
    }
}

void DynArray::insertElem(const int x)
{
    if (index == 20)
    {
        int* save = new int [20];
        for (int i = 0; i < 20; i++)
        {
            save[i] = arr[i];
        }
        liste.push_back(save);  // Hier wird das Array in die Liste kopiert.
        index = 0;
        arr[index] = x;  // Array neu mit Werten füllen
    }
    else
    {
        arr[index] = x;
    }
    index++;  // Index erhöhen
    size++;     // Gesamtanzahl
}

std::ostream& operator<< (std::ostream& o, const DynArray& x)
{
    // erst die liste ausgeben
    if (!x.liste.empty())
    {
        o << "Listeneinträge:\n";
        std::list<int*>::const_iterator it;
        for (it = x.liste.begin(); it != x.liste.end(); ++it)
        {
            o << "\n-----------------------------------------\n";
            for (int i = 0; i < 20; i++)
            {
                o << (*it)[i] << "\n";   // Zugriff auf ein Element
            }
            o << "-----------------------------------------\n";
        }
    }
    // aktuelle Ausgabe
    o << "\naktuelle Elemente:\n";
    for (int i = 0; i < x.index; i++)
    {
        o << x.arr[i] << "\n";
    }
}
C++:
#include "test.h"

int main()
{
    DynArray test;
    for (int i = 0; i < 40; i++)
    {
        test.insertElem(i);
    }
    test.insertElem(100);
    std::cout << test;

    return 0;
}

mfg :)
 
@Matthias Danke genau das war das Problem ich frage mich nur warum, ich verstehe nicht warum ich diesmal einen const_iterator benötige. Wenn ich mit Listen gearbeitet habe reichte immer ein normaler Iterator.
Da Instanz von DynArray an dieser Stelle als const deklariert ist, werden auch all ihre Membervariablen als const behandelt. Auf const-Objekten dürfen nur Methoden aufgerufen werden, die als const deklariert sind (also die das Objekt nicht verändern). Mit einem normalen iterator könnte man die Liste aber möglicherweise verändern, deswegen ist die Überladung iterator list::begin() nicht als const deklariert – kann also nicht auf einer konstanten Liste aufgerufen werden. Die Überladung const_iterator list::begin() const jedoch schon, da sie einen „nicht destruktiven“ Iterator zurückgibt und deshalb als const deklariert wurde. Einigermaßen klar geworden?

@topic Wegen dem Zugriff muss man sich noch die Logik überlegen ist nicht ganz trivial :(
Mit ganzzahliger Division mit Rest (Modulo) sollte das nicht so kompliziert sein.

Übrigens: die Kopieraktion in insertElem kann man sich auch sparen. Der interessierte Leser möge sich überlegen, wie das geht ;-]

Noch etwas, was mir gerade auffällt: die Überladung von operator<< gibt keinen Wert zurück.

Grüße, Matthias

PS: Jetzt aber wirklich die letzte Belehrung für diesen Beitrag ;) Statt '\n' sollte man bei Ausgaben besser std::endl verwenden.
 
Zuletzt bearbeitet:
@Matthias Ja habe es verstanden vielen Dank für die Erklärung. An dem übergegebenen Parameter habe ich garnicht gedacht, wie schusselig von mir :)
Die Kopieraktion kann man evtl. mit memcpy vereinfachen ? Ich habe ja zuerst angenommen das die push_back() Methode automatisch nur Kopien in die Liste speichert aber da gibt es wohl auch unterschiedliches Verhalten.
Wegen std::endl. Besteht hier der Vorteil das es nicht erst geparst werden muss (Wie beim String mit Steuerzeichen) ?

mfg ;-)
 
std::endl fügt Newline-Zeichen an und ruft std::flush direkt mit auf.

C++:
template <typename _PtrT>
inline void safe_delete_arr(_PtrT& ptr)
{ 
     delete [] ptr;
     ptr = NULL;
}

template<typename _ValueT, int PartSize = 20>
class DynArray
{
public:
    typedef _ValueT value_type;
    DynArray()
        : m_index(0), m_data(new value_type[PartSize])
    {}
 
    ~DynArray()
    {
        if (!m_storate.empty()) std::for_each(m_storage.begin(), m_storage.end(), safe_delete_arr<value_type*>);
        safe_delete_arr(m_data);
    }
 
    const std::size_t size() const { return (m_storage.size() * PartSize + m_index + 1); }
    value_type& operator[](const std::size_t rhs)
    {
        if (rhs >= size()) throw std::out_of_range("index");
        // ...
    }
    void insert(value_type const& value)
    {
        if (index >= PartSize)
        {
            m_storage.push_back(m_data);
            m_data = new value_type[PartSize];
            m_index = 0;
        }
        m_data[m_index++] = rhs; 
    }

private:
    std::list<value_type> m_storage;
    value_type* m_data;
    std::size_t m_index;
 };
so ist das wohl etwas dyn. ähnlicher ;)
 
@devDevil Danke für die Erklärung und dem eleganten Code. Ich habe mir die Freiheit genommen ihn syntaktisch zu korrigieren und zu modifizieren. Eine letzte ungeklärte Frage gibt es: Der Iterator in Zeile 44 und 73 lässt sich nicht dynamisch erstellen, dann kommt expected ';' before "it" Was muss man beachten ?
C++:
#ifndef DYNARRAY_H
#define DYNARRAY_H

#include<iostream>
#include<list>
#include<stdexcept>

template <typename _PtrT>
inline void safe_delete_arr(_PtrT& ptr)
{
     delete [] ptr;
     ptr = NULL;
}

template<typename _ValueT, int PartSize = 20>
class DynArray
{
public:
    typedef _ValueT value_type;
    DynArray()
        : m_index(0), m_data(new value_type[PartSize])
    {}

    ~DynArray()
    {
        if (!m_storage.empty())
            std::for_each(m_storage.begin(), m_storage.end(), safe_delete_arr<value_type*>);
        safe_delete_arr(m_data);
    }

    const std::size_t size() const { return (m_storage.size() * PartSize + m_index); }
    value_type& operator[](const std::size_t rhs)
    {
        if (rhs >= size()) throw std::out_of_range("index");
        if (rhs >= m_storage.size() * PartSize)
        {
            return m_data[rhs % PartSize];
        }
        else
        {
            uint16_t count = 0;
            uint16_t teiler = rhs / PartSize;
            uint16_t rest = rhs % PartSize;
            std::list<int*>::iterator it;       // value_type
            for (it = m_storage.begin(); it != m_storage.end(); ++it)
            {
                if (count == teiler)    // richtiger Block
                {
                    break;
                }
                count++;
            }
            return (*it)[rest];
        }
    }
    void insert(value_type const& value)
    {
        if (m_index >= PartSize)
        {
            m_storage.push_back(m_data);
            m_data = new value_type[PartSize];
            m_index = 0;
        }
        m_data[m_index++] = value;
    }
    template<typename value_type>
    friend std::ostream& operator<< (std::ostream& o, const DynArray<value_type>& x)
    {
        // erst die liste ausgeben
    if (!x.m_storage.empty())
    {
        o << "Listenelemente:\n";
        std::list<int*>::const_iterator it; // hier geht kein value_type !
        for (it = x.m_storage.begin(); it != x.m_storage.end(); ++it) // Warum geht das hier nicht ?
        {
            o << "\n-----------------------------------------\n";
            for (int i = 0; i < 20; i++)
            {
                o << (*it)[i] << "\n";   // Zugriff auf ein Element
            }
            o << "-----------------------------------------\n";
        }
    }
    // aktuelle Ausgabe
    o << "\naktuelle Elemente:\n";
    for (uint8_t i = 0; i < x.m_index; i++)
    {
        o << x.m_data[i] << "\n";
    }
    return o;
    }

private:
    std::list<value_type*> m_storage;
    std::size_t m_index;
    value_type* m_data;
};

#endif

mfg ;-)
 
Sorry kann sien das welche drin waren, hab's nur flux hier rein getippt ...

also ehm du solltest beachten, dass es sich jetzt bei der Klasse um ein Template handelt, du d.h. nichtmehr int* sondern value_type* als Template-Parameter für std::list hast ;) Und bei deinem stream-operator hast du auch ehm vergessen das es sich nichtmehr um 20 sondern um PartSize handelt.

C++:
value_type& operator[](const std::size_t rhs)
{
    if (rhs >= size()) throw std::out_of_range("index");
    if (rhs >= size() - (m_index + 1)) return m_data[rhs % PartSize];
         
    std::list<value_type*>::const_iterator it(m_storage.begin());
    std::advance(it, static_cast<std::size_t>(rhs / PartSize));
    return (*it)[rhs % PartSize];
}
wäre wohl auch hier der elegantere Weg ;)

Bei den Includes fehlen dir übrigens
C++:
#include <algorithm> // std::for_each
#include <iterator> // std::advance
... ;)

Und bei dem stream-operator fehlt für den Parameter da noch nen Template-Parameter (hast PartSize vergessen ...)
 
Hm hab es mal kurz nochmal aufgeräumt ;) Ist aber wieder nicht kompiliert ... ehm nja das Problem ist nur das du eigtl. ne iterator-Klasse für deinen DynArray schreiben müsstest und dann den ostream-Operator garnicht darin überladen dürftest. (Locals usw.).
C++:
#if !defined DYNARRAY_HPP__INCLUDED
#define DYNARRAY_HPP__INCLUDED
 
#pragma once
 
#include <iostream>
#include <list>
#include <stdexcept>
#include <algorithm>
#include <iterator>
 
namespace memory
{
    template <typename _PtrT>
    inline void safe_delete_arr(_PtrT& ptr)
    {
         delete [] ptr;
         ptr = NULL;
    }

    template <typename _PtrT>
    inline void safe_delete_ptr(_PtrT& ptr)
    {
        delete ptr;
        ptr = NULL;
    }
}; // memory

template<typename _ValueT, int PartSize = 20>
class DynArray
{
public:
    typedef _ValueT value_type;
    typedef std::list<value_type*> storage_type;
    typedef std::size_t size_type;
    
    DynArray()
        : m_index(0), m_data(new value_type[PartSize])
    {}
 
    ~DynArray()
    {
        if (!m_storage.empty())
            std::for_each(m_storage.begin(), m_storage.end(), memory::safe_delete_arr<value_type*>);
        memory::safe_delete_arr(m_data);
    }
 
    const size_type size() const { return (m_storage.size() * PartSize + m_index); }
    value_type& operator[](const std::size_t rhs)
    {
        if (rhs >= size()) throw std::out_of_range("index");
        if (rhs > (size() - m_index) return m_data[rhs % PartSize];
         
        storage_type::const_iterator it(m_storage.begin());
        std::advance(it, static_cast<std::size_t>(rhs / PartSize));
        return (*it)[rhs % PartSize];
    }
    
    void insert(value_type const& value)
    {
        if (m_index >= PartSize)
        {
            m_storage.push_back(m_data);
            m_data = new value_type[PartSize];
            m_index = 0;
        }
        m_data[m_index++] = value;
    }
    template<typename _ValueT, int PartSize>
    friend std::ostream& operator<< (std::ostream& out, DynArray<_ValueT, PartSize> const& rhs)
    {
        DynArray<_ValueT, PartSize>::storage_type const& storage(rhs.m_storage);
        if (!rhs.m_storage.empty())
            for (DynArray<_ValueT, PartSize>::storage_type it(storage.begin()); it != storage.end(); ++it)
            {
                std::copy(*it, (*it) + PartSize, std::ostream_iterator<_ValueT>(" ", out));
                out << "\n";
            }

        std::copy(rhs.m_data, rhs.m_index, std::ostream_iterator<_ValueT>(" ", out);
        return out;
    }
 
private:
    storage_type m_storage;
    size_type m_index;
    storage_type::value_type m_data;
};
 
#endif // DYNARRAY_HPP__INCLUDED
Kann sein das nen paar typename fehlen ...

achja genutzt wird das ganze jetzt so:
C++:
#include "DynArray.hpp"
#include <iostream>

int main()
{
    DynArray<int> myArray; // or DynArray<bool, 16> etc.
    for (std::size_t i(0); i < 50; ++i) myArray.insert(i);
    
    std::cout << myArray << std::endl;
}
 
Zuletzt bearbeitet:
Das sieht wirklich sehr elegant aus, da ich auch viele Sachen aus der STL noch nicht kenne (Algorithm, Iterator) aber ich würde dich bitten das mal zu kompilieren, denn ich bekomme da eine Menge Fehler. Wir möchten doch alle hier fehlerfreie Versionen ;)
Du hattest meinen Beitrag nicht ganz verstanden, die Frage war ja wie man einen Iterator erstellt wenn man eine Template Klasse benutzt ;)

Werde mir mal genauer angucken welche schönen Funktionen du da benutzt hast :)

1.) #pragma once - Habe gelesen das verhindert auch die mehrmalige Einbindung des Headers und/oder der Sourcen zu einem Projekt also ähnlich dem #ifndef und #define Präprozessor Direktiven
2.) Wozu safe_delete_ptr() ? Glaube das das nirgends aufgerufen wird ?
3.) storage_type::value_type m_data; // Was ist das denn für ein Konstrukt ?

mfg
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück