Forum: Compiler & IDEs Arrays in Klassen


von blue (Gast)


Lesenswert?

Hallo zusammen,

ich habe mal wieder ein kleines Problem undzwar mit Arrays.

Ich will eine Klasse schreiben, die ein Array besitzt. Die Größe dieses 
Arrays soll aber abhängig von der initialisierung der Klasse sein. Ich 
hatte mir das ganze so vorgestellt:
1
 class t{
2
          public:
3
             int i[];
4
5
             t(int j){
6
                   i[j];
7
             }
8
        }

aber so funktioniert das leider nicht. Kennt wer ne alternative wie ich 
das hinbekommen könnte?

viele grüße blue

von dito (Gast)


Lesenswert?

Arrays müssen immer statisch initialisiert werden, d.h. die Größe muss 
zur Übersetzungszeit bekannt sein. Um zur Laufzeit Speicher anzufordern 
musst du malloc() verwenden.

von Karl H. (kbuchegg)


Lesenswert?

dito schrieb:
> Arrays müssen immer statisch initialisiert werden, d.h. die Größe muss
> zur Übersetzungszeit bekannt sein. Um zur Laufzeit Speicher anzufordern
> musst du malloc() verwenden.

@blue

Lass malloc mal links liegen. In C++ macht man das anders.

Schau dir in deinem C++ Buch den Abschnitt über die STL an, und da 
wiederrum über std::vector
Wenn du einen neueren Compiler hast, kannst du auch mal nachsehen, ob er 
std::tr1::array unterstützt.

von Lukas (Gast)


Lesenswert?

Du könntest ein dynamisches Array, einen std::vector, oder Templates 
verwenden.

Dynamisch zb so:

class T {
  public:
    int * arr;
    int size;

    T(int s) size(s) {
      arr = new int[s];       //malloc() geht auch c++ sieht aber new 
vor
    }

    ~T() { //destruktor notwendig damit kein memory leak entsteht
      delete [] arr;
    }
};

Persönlich würde ich (wenn es nicht Speicherkritisch oder 
Performancekritisch zugeht) einen std::vector (oder std::list) 
verwenden, allein wegen des Komforts...

Lukas

von Klaus W. (mfgkw)


Lesenswert?

ja, aber vielleicht arr und size dann doch private oder protected 
zumindest.

von Karl H. (kbuchegg)


Lesenswert?

... und einen op= und einen Copy Constructor.

Und genau wegen all diesen Dingen, die man noch braucht um ein Klasse 
bei Verwendung von dynamischer Allokierung sicher zu machen, ist es viel 
einfacher diese Allokierung einem Spezialobjekt zu überlassen, zb. 
std::vector

Dann braucht man weder Dtor, noch op=, noch CCtor.
Und fehlerfrei im Falle, dass die erste Schätzung der Anzahl der 
Elemente zu klein war, ist es als Zugabe auch noch.

Und Performance ist kein Thema.
Wenn man std::vector halbwegs intelligent einsetzt, hat man keine 
Performance Einbusen im Vergleich zu einem selbst angelegtem Array.

von blue (Gast)


Lesenswert?

Danke für die schnellen Antworten.

Ich hatte aber vergessen zu sagen, dass das ganze für avr gedacht ist. 
Da gibt es leider keine STL. Werd aber mal Lukas Vorschlag probieren.

Danke nochmals.

viele Grüße blue

von Klaus W. (mfgkw)


Lesenswert?

@KHB:
Aber halt nur, wenn einer der Standardcontainer auch passt.
Je nachdem, was man braucht.

von Karl H. (kbuchegg)


Lesenswert?

blue schrieb:
> Danke für die schnellen Antworten.
>
> Ich hatte aber vergessen zu sagen, dass das ganze für avr gedacht ist.

Welchen?

> Da gibt es leider keine STL. Werd aber mal Lukas Vorschlag probieren.

Auf einem µC mit arg begrenztem Speicher willst du dynamische 
Speicherallokierung vermeiden, wie der Teufel das Weihwasser.

Was machst du, wenn der Speicher zur Neige geht?
Du kannst nicht einfach "Out of Memory" hinschreiben und zum 
Betriebssystem zurückkehren!

a) hast du kein Betriebssystem
b) Steuerungen müssen unter allen Umständen weiterlaufen.
   So etwas wie einen "Out of Memory" darf es nicht geben!

von Klaus W. (mfgkw)


Lesenswert?

blue schrieb:
> Ich hatte aber vergessen zu sagen, dass das ganze für avr gedacht ist.

Ob man da aber mit copy-ctor, operator= etc. spielen will, sei mal
dahingestellt.
Wenn man weiß, was man macht, ist es i. Ordnung.
Aber im Allgemeinen sind die Warnungen nicht von der Hand
zu weisen:

Karl heinz Buchegger schrieb:
> .. und einen op= und einen Copy Constructor.
>
> Und genau wegen all diesen Dingen, die man noch braucht um ein Klasse
> bei Verwendung von dynamischer Allokierung sicher zu machen,...

von Klaus W. (mfgkw)


Lesenswert?

Karl heinz Buchegger schrieb:
> Was machst du, wenn der Speicher zur Neige geht?

Hoffentlich keine Ausnahme werfen :-)

von blue (Gast)


Lesenswert?

Ich nutze einen Roboter mit einem AT90CAN128.

Das Ganze wird als Tupel für ein DBMS gebraucht. Und für spezielle 
Funktionen brauch ich eine klare Struktur meiner Daten. Und da 
gespeicherte Tupel unterschiedlich viele Attribute haben können, muss 
ich die Größe des Arrays meinem Datensatz anpassen. Ohne Array wird das 
ganze (inkl. der zu Programmierenden Funktion) um einiges Komplizierter. 
Die Menge der Tupel im Hauptspeicher soll ja garnicht so groß werden und 
die Tupel (also auch das Array) werden später wieder frei.

Betriebssystem: soll garkeins haben, um Speicher zu sparen.

viele Grüße blue

von Klaus W. (mfgkw)


Lesenswert?

blue schrieb:
> die Tupel (also auch das Array) werden später wieder frei.

Aber auch dann kann es passieren, daß der Speicher zwar frei
ist, aber irgendwann zu fragmentiert, um etwas neues anlegen zu
können.

Mit etwas Verstand könnte man sich notfalls eine eigene
Speicherverwaltung überlegen.
Die Fehlerbehandlung wird auf jeden Fall spannend.

von Karl H. (kbuchegg)


Lesenswert?

blue schrieb:
> Ich nutze einen Roboter mit einem AT90CAN128.

d.h 4KB SRAM

> Und da
> gespeicherte Tupel unterschiedlich viele Attribute haben können,

gibt es eine Obergrenze?
Wenn es eine gibt, dann nutze sie.
Lege alles statisch für diese Obergrenze aus.

> muss
> ich die Größe des Arrays meinem Datensatz anpassen. Ohne Array wird das
> ganze (inkl. der zu Programmierenden Funktion) um einiges Komplizierter.
> Die Menge der Tupel im Hauptspeicher soll ja garnicht so groß werden und
> die Tupel (also auch das Array) werden später wieder frei.

Dir ist klar, dass das einfache Zusammenzählen der Speicherallokierungen 
für den Komplettverbrauch eine Milchmädchenrechnung ist, die ganz 
schnell nach hinten losgehen kann? Stichwort: Speicherfragmentierung

Du kannst zb

 4K frei haben

 1K allokieren
 2K allokieren
 1K allokieren

jetzt gibst du die beiden 1K Blöcke wieder frei. Nach Adam Riese sind 2K 
allokiert und 2K frei. Und trotzdem gibt dir malloc einen NULL Pointer 
wenn du 1.5K anforderst.
Warum?
Weil zwar 2k frei sind, das stimmt schon, aber nicht in einem Stück! Die 
2K liegen in Form von 2 jeweils 1K großen Blöcken vor. In keinen von 
beiden passen aber deine 1.5K hinein.

(Zahlen jetzt frei erfunden um das Problem zu zeigen. Du wirst kleinere 
Zahlen haben. Dafür hast du aber auch mehr im Speicher und nicht die 
ganzen 4K für dich alleine)

von Lukas (Gast)


Lesenswert?

Wenn das dem Problem nicht entgegensteht würde ich einfach verkettete 
Listen nehmen, oder spricht da was dagegen?

von U.R. Schmitt (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Und trotzdem gibt dir malloc einen NULL POinter
> wenn du 1.5K anforderst.

Selbst bei 1K bekommt er einen null Pointer, da die Speicherverwaltung 
schon den Rest gefressen hat.

@ TE: Was genau meinst Du mit
Tupel für ein DBMS gebraucht. DBMS ist für mich database management 
System. Und ein Tpel eine Menge von (n) Elementen/Werten.

von Karl H. (kbuchegg)


Lesenswert?

Lukas schrieb:
> Wenn das dem Problem nicht entgegensteht würde ich einfach verkettete
> Listen nehmen, oder spricht da was dagegen?

mehr Speicheroverhead.
Gefahr für Fragmentierung größer

Vorteile:
mehrere kleinere Speicheranforderungen anstatt einer großen.
Dadurch ist die Gefahr einer Fragmentierung zum Opfer zu fallen 
geringer.


Ein grundätzlicher Nachteil dynamischer ALlokierung auf einem AVR mit 
wenig Speicher (und 4K sind wenig) wurde noch gar nicht angesprochen.

Bei rein statischer Allokierung muss man ein Auge darauf haben, dass 
einem der Stack nicht in die Daten hineinwächst.
Kommt dynamische Allokierung mit ins Spiel gilt dann auch die Umkehrung: 
Man muss ein Auge darauf haben, dass einem der Heap nicht in den Stack 
hineinwächst, wachsende Daten also nicht den Stack korrupten.
Wenn man von malloc eine NULL bekommt, ist es schon längst zu spät. Dann 
hat man schon längst den Stack niedergebügelt.

Alles in allem gute Gründe, möglichst alles statisch festzunageln und 
auf Obergrenzen zu dimensionieren, selbst wenn dann in Einzelfällen 
Speicher nicht benutzt wird. Aber so hat man dann wenigstens fixe 
Kennzahlen: Bis hierher und nicht weiter.

von blue (Gast)


Lesenswert?

Also ich hab mich oben falsch ausgedrückt,

das Ganze ist wie gesagt für ein DBMS. Unterschiedliche Anwendungen 
dieses DBMS haben je nach verwendetem Systemkonfiguarationen wenige 
verschiedene Tupelarten mit unterschiedlichen Längen. Die dann aber sich 
nicht ständig Ändern. Also feste Größen pro Datenbank, die sich aber von 
Anwendung zu Anwendung ändern.

Dank euch werde ich als Empfehlung für die Anwendungsprogrammierung klar 
herausstellen, das immer nur eine feste Anzahl an Tupeln deklariert 
werden sollte, die dann nicht!! freigegeben werden, sondern immer wieder 
mit neuen Werten bestückt werden. Vielleicht mach ich das auch über eine 
Schnittstelle, die dann die Tupel verwaltet/ initialisiert. (Achtung 
keine Speicherverwaltung)

Die Möglichkeit mit einer festen Obergrenze ist leider nicht so 
praktikabel, da sich diese von Anwendung zu Anwendung ändert und 
eigendlich nicht im Code des DBMS geändert werden soll.

Danke für eure Hilfe, damit habt ihr mich auch auf die potentielle 
Fehlerquelle Tupel hingewiesen. (an anderer Stelle habe ich genau das 
Problem erst behoben und hier vergesse ichs ;-))

viele grüße blue

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.