vector an dll übergeben



  • Hi Leute,
    ich hab hier ein Problem, an dem ich jetzt schon seit Tagen rumbastel und keine Lösung finde, vielleicht kann mir hier ja jemand helfen.
    Und zwar möchte ich einen Vektor an ein Funktion in einer DLL übergeben in der dann der Vektor "gefüllt" wird. Das ganze funktioniert ja auch soweit ganz gut, nur wenn der Bereich in dem die DLL aufgerufen wurde verlassen wird, dann bekomm ich einen deallocate Fehler (denke mal das ist einer)
    Und hab keine Ahnung wieso.
    Weiß hier vielleicht jemand, was ich machen muss, wenn ich einen Vector übergeben will?????

    Mfg
    mached

    P.S.: hier noch ein Beispie-Code, wie das ungefähr bei mir aussieht:

    //Der Funktionsaufruf
    void DasProgramm()
    {
     switch(message)
     {
      case WM_IRGENDEINEMESSAGE:
       {
        vector<string> Vec;
        LoadLibrary(...)
        GetVector(Vec);          //hier wird die Funktion der DLL aufgerufen
        return TRUE;              //hier kommt dann die Fehlermeldung
       }
    }
    
    //die DLL
    EXPORT BOOL GetVector(vector<string>& Vec)
    {
      //... 
      Vec.pushback("hallo");
      //...
      return TRUE;
    }
    


  • Das Programm sei a, die DLL b.

    Eine Vermutung:
    b ruft push_back auf. Der Code für push_back liegt in b (der DLL). Innerhalb von push_back muss new aufgerufen werden (wenn aus dem const char* ein std::string gemacht wird). Da es der b-Code von push_back ist, wird das new von b aufgerufen.
    Jetzt ist b fertig, a kommt an die Reihe.
    a will den Vektor zerstören, ruft also den Destruktor auf. Der Code dafür liegt aber in a, nicht in b. Daher wird innerhalb des Destruktors (wenn der std::string zerstört werden soll) das delete aufgerufen, das in a liegt -> peng.

    new in der DLL. delete in der EXE. Das kann nicht gutgehen, da DLL und EXE unterschiedliche Heaps/Allokatoren etc. besitzen. Dass die Zeiger austauschbar sind (weil im selben Adresssegment) spielt dabei keine Rolle; es handelt sich um ein Problem der C++ Runtime Library.



  • Klingt logisch, hätte ja vielleicht sein können, dass man das irgendwie hätte doch hinbiegen können.
    Aber schon mal vielen Dank für die Antwort. Jezt muss ich mir wohl eine andere Möglichkeit für mein Problem suchen (müsste theoretisch ein Array unbekannter Größe füllen lassen)

    mfg mached



  • Hi Leute,
    Hab doch noch ne Lösung gefunden, mit der ich wenigstens einen vector als Rückgabewert aus einer DLL bekommen und wollt hier noch meine Lösung posten:

    die DLL:

    //die Funktion, die den vector zurückgeben soll:
    __declspec(dllexport) std::vector<std::string>* GetVector()
    {
      std::vector<std::string> *m = new std::vector<std::string>;
      //Den vector füllen
      for(int i = 0; i < iWasauchImmer; i++)
      {
        m->push_back("Der Text");
      }
    }
    

    die .exe oder auch eine andere DLL, die die DLL benötigt:

    __declspec(dllimport) std::vector<std::string>* GetVector();
    //Dann irgendwo der Aufruf
    std::vector<std::string> *v = GetVector();
    

    Und schon hab ich den gefüllten vector aus der DLL
    Hoffe das hilft vielleicht dem ein oder anderen, da ich selber schon Tagelang auf der Suche nach so einer Lösung war auch wenn sie im Endeffekt einfacher war als gedacht.

    mfg mached



  • Und wie löschst du den vector?



  • Meinst du den Speicher wieder freigeben, oder einzelne Einträge des vectors zu löschen.
    Bzgl. der Speicherfreigabe: Soweit ich weiß muss man sich bei vectoren um den Speicher nicht kümmeren, da der vector eine dynamische Speicherverwaltung hat. Ansonsten geb ich sowieso den kompletten Speicher der DLL wieder frei, sobald ich sie nicht mehr brauche (ich binde diese dynamisch)

    mfg mached



  • Nö, das meine ich nicht.

    Du rufst in deinem Code new auf. Wo ist das dazugehörige delete?



  • Ich glaub das Problem kannst du auch dadurch lösen, wenn du die Multithreaded Standardlibrary anstatt der Singlethreaded nimmst.



  • Das delete fehlt an dieser Stelle daher, dass ich den vector ja als Rückgabewert habe. Wenn ich delete jetzt noch in der DLL ausführen würde, hätte ich ja in der .exe keine Werte mehr bzw. das ganze würde irgendwo ins leere führen.
    Ansonsten wird der Speicher, den der vector sich geholt hat im dekonstruktor vom vector selbst wieder freigegeben. Soll angeblich so sein 🙂
    Deswegen geb ich noch den kompletten Speicher der DLL vorsichtshalber dann frei, wenn die DLL selbst wieder frei gegeben wird.
    Das einzige was man noch machen kann wäre in der .exe:
    delete[] v;
    funktioniert soweit auch, nur konnte ich bisher noch nicht nachprüfen ob wirklich der Speicher des vectors freigegeben wird.

    mfg mached

    P.S.: gefunden hab ich das ganze hier: http://support.microsoft.com/default.aspx?scid=kb;en-us;172396



  • Du hast mich anscheinend nicht richtig verstanden.
    Speicher, der mit new in der DLL angefordert wurde, muss auch in derselben DLL wieder freigegeben werden. Sonst bewegst du dich auf sehr sehr dünnem Eis. Den Speicher nicht freizugeben ist keine ernstzunehmende Lösung.

    So blöd es sein mag, die DLL muss also eine Funktion bereitstellen, die nichts anderes als "delete v;" macht. (delete**[]** v war hoffentlich nur ein Schreibfehler deinerseits.)



  • Also verstanden hatte ich dich schon richtig, aber ich wusste nicht genau, ob der vector den Speicher von alleine wieder freigibt, aber diese Frage hast du mir damit beantwortet, danke.
    Wegen der Funktion, die den Speicher wieder freigibt, da hatte ich ja schon geschrieben, dass ich den Speicher wieder freigebe, wenn die DLL an sich wieder frei gegeben wird.(Ich brauch die immer nur kurz) Und man bekommt ja einige Messages, wie z.B. DLL_THREAD_DETACH, DLL_PROCESS_DETACH,... und in
    denen geb ich den Speicher wieder frei, auch den des vectors. Es sei denn, es gibt noch andere Möglichkeiten, die Auftreten können, so dass eine Funktion zur Speicherfreigabe sinnvoller wäre.
    Das delete[] war wirklich ein Tipp- bzw. Gedankenfehler, sorry.
    Ansonsten vielen Dank für die Hinweise, mir ist dadurch der Umgang mit vectoren um einiges klarer geweorden.

    mfg mached



  • Bei meisten (ich kenn keinen bei dem dies nicht der fall ist!) Win32 Compiler werden new und delete mit Hilfe der HeapAlloc Funktionen aus der Kernel32.dll implementiert. Um diese aber benutzen zu können muss man aber ein Heap mit HeapCreate erschaffen dies geschiet im Start-up Module. Das Problem ist aber, dass die dll und exe 2 Start-up Modules haben und somit zwei Heaps und wenn du versuchst ein Wert im Heap 1 durch aufrufen von HeapFree für Heap 2 freizugeben macht es bum.

    Desweiteren ist ein Heap Handle Processlokal, das heist selbst wenn du den Handle bekommen solltest und ihn an die exe übergeben würdest, würde es nicht klappen.

    Eine Lösung ist das benutzen von CreateFileMapping oder du machst was ich in solchen Fällen mache. Du packst einfach diese Funktion in die dll:

    void free_vector_int(vector<int>*a)
    {
        delete a;
    }
    

    Für jeden Class Pointer musst du eine free Funktion schreiben wegen des Destructors. Ach und vector<int> ist eine andere Class als vector<char>!



  • Irgendwer schrieb:

    Bei meisten (ich kenn keinen bei dem dies nicht der fall ist!) Win32 Compiler werden new und delete mit Hilfe der HeapAlloc Funktionen aus der Kernel32.dll implementiert. Um diese aber benutzen zu können muss man aber ein Heap mit HeapCreate erschaffen dies geschiet im Start-up Module. Das Problem ist aber, dass die dll und exe 2 Start-up Modules haben und somit zwei Heaps und wenn du versuchst ein Wert im Heap 1 durch aufrufen von HeapFree für Heap 2 freizugeben macht es bum.

    Was hab ich denn geschrieben? 🙄

    Irgendwer schrieb:

    Desweiteren ist ein Heap Handle Processlokal, das heist selbst wenn du den Handle bekommen solltest und ihn an die exe übergeben würdest, würde es nicht klappen.

    Bin mir da gerade nicht 100% sicher, aber können DLL und EXE nicht die gleichen Handles benutzen?
    Das sind ja keine zwei Prozesse.

    Irgendwer schrieb:

    Eine Lösung ist das benutzen von CreateFileMapping oder du machst was ich in solchen Fällen mache. Du packst einfach diese Funktion in die dll:

    void free_vector_int(vector<int>*a)
    {
        delete a;
    }
    

    Für jeden Class Pointer musst du eine free Funktion schreiben wegen des Destructors.

    Was hab ich denn geschrieben? 🙄


Anmelden zum Antworten