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 ...
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.
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 ... ;)
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.
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.
Danke, ist jetzt klarer geworden.
Eine kleine Frage noch: Wie gebe ich den Speicher dann frei? Reicht
delete[] ptr? Oder werden
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.
|