Forum: PC-Programmierung Array von Zeigern


von Maxim (maxim) Benutzerseite


Lesenswert?

Ich benoetige 9 Zeiger auf jeweils ein Objekt vom Typ cl_mem. Das kann 
ich doch in einem Array anordnen, um darauf elegant per Index 
zuzugreifen. Erzeugt werden diese Objekte von einer Funktion cl_mem 
clCreateBuffer(...). Also kann ich das folgendermassen loesen:
1
cl_mem *ptr[9];
2
for(int k = 0; k < 9; k++) {
3
  *ptr[k] = clCreateBuffer(...);
4
}

Richtig?

Jetzt gibt es Funktionen, welche nur die Adresse dieser Objekte 
brauchen, z.B.:
1
clAmdFftStatus clAmdFftEnqueueTransform (..., cl_mem * inputBuffers, ...)
Haette ich statt einem Array von Zeigern auf cl_mem-Objekte die Objekte 
selbst, also z.B. *cl_mem aBuffer = clCreateBuffer(...)*, dann koennte 
ich deren Adresse so uebergeben:
1
clAmdFftStatus clAmdFftEnqueueTransform (..., &aBuffer, ...)
Aber wie mache ich das nun mit den Zeigern im Array? Etwa wie folgt?
1
clAmdFftEnqueueTransform (..., ptr[5], ...)

Dann gibt es noch Funktionen, die nicht die Adresse sondern das Objekt 
selbst erwarten, z.B.:
1
cl_int clEnqueueWriteBuffer (.., cl_mem buffer, ..)
In diesem Fall sollte das mit dem Array so gehen:
1
clEnqueueWriteBuffer (.., *ptr[5], ..)
Stimmt's?

Ich frage nur nach, weil ich stanedig Fehlermeldungen beim Kompilieren 
erhalte und ausschliessen moechte, dass die irgendwo hier entstehen ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Maxim S. schrieb:
> Ich frage nur nach, weil ich stanedig Fehlermeldungen beim Kompilieren
> erhalte und ausschliessen moechte, dass die irgendwo hier entstehen ...

Nun, es wäre schon praktisch, wenn Du erwähnen würdest, was für 
Fehlermeldungen das sind.

von Maxim (maxim) Benutzerseite


Lesenswert?

Die Fehlermeldungen beim Kompilieren hatten andere Gruende. Nachdem ich 
diese beseitigt habe, bekam ich "segmentation Fault" in der Zeile
1
*ptr[k] = clCreateBuffer(...);

Ich habe alles umgeschrieben und jetzt funktioniert es ohne Probleme:
1
cl_mem *ptr = new ptr[9];
2
for(int k = 0; k < 9; k++) {
3
  ptr[k] = clCreateBuffer(...);
4
}

Fuer clAmdFftStatus clAmdFftEnqueueTransform (..., &aBuffer, ...) 
schreibe ich nun
1
clAmdFftEnqueueTransform (..., &ptr[5], ...)

und fuer cl_int clEnqueueWriteBuffer (.., cl_mem buffer, ..) schreibe 
ich
1
clEnqueueWriteBuffer (.., ptr[5], ..)

Ich wuerde nur gerne wissen, warum das so funktioniert und nicht wie 
davor vermutet ... ;)

von Fabian O. (xfr)


Lesenswert?

Maxim S. schrieb:
> cl_mem *ptr[9];
> for(int k = 0; k < 9; k++) {
>   *ptr[k] = clCreateBuffer(...);
> }

Das geht so nicht. In dem Array ist ja nur Platz für 9 Zeiger, nicht für 
9 Objekte! Du schreibst also in der Schleife an irgendwelche 
Speicheradressen, die zufällig im Array stehen. Du musst ein Array aus 
cl_mem-Objekten anlegen und nicht aus Zeigern.

von Karl H. (kbuchegg)


Lesenswert?

Maxim S. schrieb:

> Ich wuerde nur gerne wissen, warum das so funktioniert und nicht wie
> davor vermutet ... ;)


Wo hast du dein Gedankenproblem.

Wenn

  int * ptr[9];

ein Array von 9 Zeigern auf int ist, dann ist

   ptr[4]

einer dieser Zeiger.

Du kriegst von der Funktion einen Zeiger und willst ihn im Array 
speichern. Also Zeiger speichern.

   ptr[4] ist ein Speicherplatz, an dem man einen Zeiger speichern kann

   ptr[4] = ...Funktion die einen Zeiger liefert.


Du schreibst ja auch

  int a[5];

  a[3] = 4;

um den Wert 4 im Array zu speichern. Oder wenn du eine Funktion hast, 
die einen Wert liefert, dann eben

  a[4] = foo();


Also warum soll da jetzt ein

  *ptr[k] = clCreateBuffer(...);

richtig sein?
In ptr[k] wird die Adresse des Buffers (vulgo ein Zeiger auf den Buffer) 
gespeichert.

Bei Zeigern musst du unterscheiden wovon die Rede ist.
Ist von der Adresse die Rede, also dem numerischen Wert wo im Speicher 
etwas gespeichert ist.
Oder ist von diesem "etwas" selber die Rede.

Je nachdem brauchst du keinen * oder du brauchst ihn.

   int   j = 5;
   int * a = &j

   a      .... das ist der numerische Wert des Zeigers. Also die Adresse
               die in ihm gespeicher ist. In diesem Fall eben die
               Adresse von j.

   *a     .... hier ist von dem Teil die Rede, der über die Adresse
               erreicht werden kann. Das 'Objekt' selber, auf das
               der Zeiger zeigt. Ein
               *a = 5;
               würde j verändern, weil a ja auf j zeigt.

von Maxim (maxim) Benutzerseite


Lesenswert?

Danke, ist jetzt klarer geworden.

von Maxim (maxim) Benutzerseite


Lesenswert?

Eine kleine Frage noch: Wie gebe ich den Speicher dann frei? Reicht 
delete[] ptr? Oder werden

von Karl H. (kbuchegg)


Lesenswert?

Maxim S. schrieb:
> Eine kleine Frage noch: Wie gebe ich den Speicher dann frei? Reicht
> delete[] ptr? Oder werden


Das kann dir keiner sagen, weil keiner weiß, wie der Speicher reserviert
wurde.

Für jedes new brauchst du ein delete
Für jedes new[] brauchst du ein delete[]

Und auch umgekehrt: ist etwas nicht mit new allokiert worden, dann
braucht es auch kein delete.


Und das wars dann auch schon. Wenn das erfüllt ist, dann hast du keine
Speicherlecks. Eigentlich eine ganz einfache Sache. Interessant wird die
Sache erst dann, wenn du wie ein Wilder Pointer durch die Gegend
kopierst und zum Schluss nicht mehr klar ist, welcher Codeteil jetzt
eigentlich für den delete zuständig ist.
Daher lautet hier die Empfehlung: Tu's nicht. Die Klasse, die den
Speicher allokiert ist auch dafür zuständig ihn wieder zu deleten. Lass
die Ding beinander! Mach dir klar, dass du 2 'Arten' von Pointer hast:
Owning Pointer und Non Owning Pointer. Ein Owning Pointer ist der
Pointer der das Objekt 'besitzt'. Er ist für das Management des Objekts
zuständig. Owning Pointer gibt es immer nur einen. Alle anderen Pointer
sind Non Owning Pointer. Sie verweisen zwar auf das Objekt, das Objekt
kann über diesen Pointer benutzt werden, aber sie haben nichts mit dem
Lifetime-Management zu tun. Das wird einzig und ausschliesslich über den
Owning Pointer abgewickelt.

Mit so einer Strategie und ein wenig Disziplin verliert dann das
dynamische Memory-Manegement seinen Schrecken. Alle die, die immer
jammern, dass das so kompliziert und fehleranfällig sei, sind meistens
die, die einen riesen Saustall in der Zuständigkeit (Owning Pointer)
veranstaltet haben. Klar, dass sie irgendwann den Überblick verlieren,
wer wann und warum welches Objekt über welchen Pointer löscht. Von vorne
herein klare Verhältnisse, Resource Management in eine eigene Klasse
auslagern und ein bischen Disziplin einhalten und dann ist das alles 
kein Thema mehr.

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.