Probleme mit Pointerübergabe



  • Hallo,

    ich denke ich habe ein relativ triviales Problem, bin aber noch nicht sehr fit in C++ und beiße mir daran gerade die Zähne aus. Wäre für jede Hilfe sehr dankbar.

    Ich habe eine Klasse Image in der ich Bildaten in einem vector "_data" speichere der Pointer auf Instanzen von vigra MultiArrays (vigra ist eine Bildverarbeitungsbibliothek) enthält. In vigra::MultiArrays gibt es die Methode data() die einen Pointer auf das Datenarray zurückgibt. Ich möchte nun einfach diesen Pointer nach Außen zugänglich machen. Leider kann ich den Pointer nicht an MultiArrays außerhalb übergeben und verstehe das Problem nicht.

    In Klasse Image:

    void Image::get_channel(int channel,float* data_ptr) {  
        if(channel>=0 && channel<this->_data.size()) {
            cout << "data_ptr before " << data_ptr << endl;
            cout << "data() before " << this->_data[channel]->data() << endl;
    
            data_ptr = this->_data[channel]->data();
    
            cout << "data_ptr after " << data_ptr << endl;
        }
    }
    

    Außerhalb:

    OpenLF::Image img(fname.c_str());
    vigra::MultiArray<2,float> tmp = vigra::MultiArray<2,float>(vigra::Shape2(512,512));
    img.get_channel(0,tmp.data());
    cout << "data_ptr outside " << tmp.data() << endl;
    

    Konsolen Ausgabe:
    data_ptr before 0x7f6c93efe010
    data() before 0x7f6ca32ae010
    data_ptr after 0x7f6ca32ae010
    data_ptr outside 0x7f6c93efe010



  • Mit zeigerumbiegen kommst du hier nicht weiter (du müsstest auch eine Referenz auf den Pointer übergeben). Entweder vigra Multiarray hat einen Zuweisungsoperator, dann musst du eben das Array übergeben, oder du musst die Daten kopieren.



  • Auch wenn dir gleich Leute das Gegenteil sagen werden: In C++ gibt es nur call by value. Das heißt Parameter werden kopiert. Wenn du Image::get_channel einen float * übergibst, dann wird dieser kopiert, das heißt data_ptr ist nicht derselbe Pointer den du übergeben hast, es ist ein anderer Pointer der auf dasselbe zeigt.
    Dann lässt du in Image::get_channel die Kopie auf die richtigen Daten zeigen und dann kehrt die Funktion zurück, der kopierte Zeiger mit dem neuen Wert verschwindet und der übergebene Zeiger hat immernoch den alten Wert. Mit anderen Worten können übergebene Parameter nie geändert werden.
    Lösung: Du kannst den Pointer als Referenz übergeben.

    void Image::get_channel(int channel,float *&data_ptr){
        data_ptr = this->_data[channel]->data();
    }
    

    Jetzt wird eine Referenz auf einen Pointer übergeben, kein Pointer. Die Referenz referenziert den originalen Pointer.
    Alternativ kannst du einen Pointer auf einen Pointer übergeben:

    void Image::get_channel(int channel,float **data_ptr){
        *data_ptr = this->_data[channel]->data();
    }
    


  • Oder du gibst den pointer einfach so zurück:

    float* Image::get_channel(int channel){ 
        return this->_data[channel]->data(); 
    }
    

    In C++ gibt es nur call by value. ... Du kannst den Pointer als Referenz übergeben.

    Und genau DAS nennt man dann call by reference.



  • Vielen Dank für Eure Antworten, dadurch hat es jetzt Klick gemacht was mein eigentliches Problem ist. Die Methode data() gibt mir natürlich die Adresse der Daten, was mir aber noch lange nicht erlaubt diese zu ändern, was ja auch durchaus Sinn ergibt, denke ich. Ich muss mich noch etwas ausgiebiger mit der API beschäftigen wie man das richtig macht.

    Vielen Dank nochmal und liebe Grüße



  • Die Methode data() gibt mir natürlich die Adresse der Daten, was mir aber noch lange nicht erlaubt diese zu ändern, was ja auch durchaus Sinn ergibt, denke ich. Ich muss mich noch etwas ausgiebiger mit der API beschäftigen wie man das richtig macht.

    Das klingt nicht so als ob du er verstanden hast... Du darfst die Addresse natürlich ändern (mal davon abgesehen dass es nicht viel Sinn macht), aber das versucht dein Code ja nicht.

    Der Parameter

    float *data_ptr
    

    verhält sich letztendlich auch nur wie eine lokale Variable, nur dass sie nicht von der Methode selber, sondern von dem Aufrufer festgelegt wird.
    Wenn du dann

    data_ptr = this->_data[channel]->data();
    

    schreibst, gibst du der lokalen Variable lediglich einen neuen Wert, der Aufrufer sieht davon nichts.

    Btw, mit API hat das nichts zu tun, mehr mit Grundlagen der Programmierung.



  • [quote="DarkShadow44"]

    Btw, mit API hat das nichts zu tun, mehr mit Grundlagen der Programmierung.

    Da muss ich Dir recht geben, tue mich noch etwas schwer aber das wird schon noch. Die API hat aber trotzdem geholfen. swap(MultiArray& other) ist das Zauberwort. Setzt Shape und Pointer ohne Daten zu kopieren.

    Schönen Abend noch


Log in to reply