Dll-Funktion mit Returnwert std::string (ByValue)



  • Hallo zusammen!

    Ich will eine Dll schreiben welche einen String (ByValue) zurückliefert. Zu Begin hab ich's mit

    std::string funcName(void);

    versucht.

    Leider ist der Zuweisungsoperator nicht überladen, weshalb nach dem entladen der DLL der Speicher weg ist...

    Meine Frage:

    Gibt es eine STL-Funktion um einen std:string ByValue zu kopieren???

    Gruß && Danke



  • -=Lucifer=- schrieb:

    ...
    std::string ...
    Leider ist der Zuweisungsoperator nicht überladen...

    Das glaube ich nicht ! 😃
    std::string hat seinen eigenen gut funktionierenden operator=() und auch CpyCtor.
    Ich denke, Dein Problem liegt woanders...

    Gruß,

    Simon2.



  • Aber bei der Zuweisung wird die Adresse von _ptr kopiert. Ich dachte, dass dies dem Verhalten der Default-Funktionen entspricht?!?

    Du meinst mit der Anweisung:

    string str1("str1");
    string str2("str2");
    
    str1 = str2;
    

    sollte nur der Inhalt kopiert werden? Falls ja, liegt mein Fehler woanders...

    Danke!



  • Ja, diese Zuweisung kopiert den Inhalt des Strings (das kann über Referenzzählung ablaufen, muß aber nicht - auf jeden Fall ist garantiert, daß hinterher beide Strings identische Daten enthalten und unabhängig voneinander weiterverwendet werden können).

    PS: Was ein Problem sein könnte ist die Tatsache, daß DLL und Hauptprogramm idR eine unabhängige Speicherverwaltung verwenden.



  • CStoll schrieb:

    ...
    PS: Was ein Problem sein könnte ist die Tatsache, daß DLL und Hauptprogramm idR eine unabhängige Speicherverwaltung verwenden.

    Hmmmm, wird den die Kopiersemantik von der DLL übernommen ? Habe ich mir noch nie Gedanken drüber gemacht ....

    Gruß,

    Simon2.



  • Hi!

    Die Variable die ich zurück leifern will, ist in der Dll global. Sobald ich die Dll entlade ist der String-Inhalt weg. Ich brauche eine Möglichkeit einen string mit Speicher aus meiner App zu übergeben, um dann den Inhalt zu kopieren.

    Naja, aber ich glaube, dass wird eine größere Sache. Ich werde einfach einen char* übergeben.

    Gruß



  • -=Lucifer=- schrieb:

    ...Ich werde einfach einen char* übergeben.

    Gruß

    Das wird die Sache nicht besser machen - dann hast Du ja sogar explizit einen Zeiger auf ein Stück "DLL-Speicher".
    Du schreibst, Du wolltest "eine globale Variable zurückliefern" - das verwirrt mich ein wenig. Vllt. verstehe ich das auch nur falsch .... aber willst Du nicht "die Werte hinter dieser Variable in eine andere Variable kopieren" ?

    Gruß,

    Simon2.



  • nen std::xxx ueber dll schnittstellen zu exportieren, wuerd ich Dir dringendst nicht empfehlen.

    STL container sind auscodierte klassen(templates). man weiss nicht so genau was sie im hintzergrund machen, haben aber keine schnittstellen eigenschaften, so das Quelle und Ziel das object 100% gleich interpretieren muessen.

    Das ist bei ner exe-dll struktur oft nicht gegeben, weil exe und dll unterscheidliche uebersetzungseinheiten sind, und damit total unterschiedliche implementationen von basisfunktionalitaeten (unterschiedliche runtimes) haben koennen. Ausserdem koennt die exe ne ganz andere STL impl verwenden als die dll.

    Bei nem guten Modulkonzept sollten sowenig wie moeglich Implementationsdetails ueber die schnittstelle wandren, also am besten nur pure abstrakt klassen verwenden.

    soll die dll mit mit anderen compiler(versionen) als die exe uebersetzt werden koennen, wird dir C++ eh das leben zur hoelle machen, und du solltest reine C Schnittstellen verwenden.

    Naja, aber ich glaube, dass wird eine größere Sache. Ich werde einfach einen char* übergeben.

    Im Hinblick auf robustheit der Schnittstelle sicher ned die schlechteste Wahl (sogar sehr ueblich). Also c-Strings statt irgendwelche impls zu verwenden. Auf zeiger innerhalb ner dll verweissen wiederum nich so ^^

    Ciao ...



  • Das wird die Sache nicht besser machen - dann hast Du ja sogar explizit einen Zeiger auf ein Stück "DLL-Speicher".

    Wenn der string auf was nicht dll globales zeigt, bekommt er probleme ja.
    er muesste die Lebenszeit des zeigers fuer die anwendung genau definieren, und die Anwendung muesste sich bei bedarf soweiso ne kopie ziehen. Bei rueckruf (event) funktionen, die man bei Dlls gern verwendet, ist das eher kein problem. Laenger als paar funktionsaufrufe lang sollt man soweiso ned auf speicher einer dll verweisen ... sondern immer asap ne kopie ziehen.

    Will man stattdessen sich nur zu nem beliebigen Zeitpunkt nen String holen koennen der sich zur laufzeit gar aendern kann, bieten sich die klassische C-Syntax wieder an ....

    int GetMyString(char * buffer, size_t * buffersize);

    oder man verwendet wiederum Callback funktionen Interfaces ... also quasi von hinten anschleichen. Du sagst der Dll das du den string haben willst die dll ruft wiederum ne Set funktion (callback) auf die dir den string setzt. damit ist der string (zeiger) nicht mehr rueckgabewert sondern parameter und du kannst davon ausgehen das der zeiger auf die dauer des funktionsaufrufes gueltig bleibt (multithreading beachten wenn man muss) und die Anwendung muss sich sofort ne kopie ziehen ....

    Robuste Dll schnittstellen sind meist ne ziemliche Rackerei, also gegenueber dem C++ in einer anwendung eher sehr umstaendlich. Aber meistens lohnt sich der aufwand.

    Ciao ...



  • RHBaum schrieb:

    nen std::xxx ueber dll schnittstellen zu exportieren, wuerd ich Dir dringendst nicht empfehlen.

    STL container sind auscodierte klassen(templates). man weiss nicht so genau was sie im hintzergrund machen, haben aber keine schnittstellen eigenschaften, so das Quelle und Ziel das object 100% gleich interpretieren muessen.

    Das ist bei ner exe-dll struktur oft nicht gegeben, weil exe und dll unterscheidliche uebersetzungseinheiten sind, und damit total unterschiedliche implementationen von basisfunktionalitaeten (unterschiedliche runtimes) haben koennen. Ausserdem koennt die exe ne ganz andere STL impl verwenden als die dll....

    Hi,

    also ich habe bislang keine Probleme mit unterschiedlichen ÜEs gehabt, solange ich dieselbe "Entwicklungsumgebung" hatte - und ih bin hier davon ausgegangen, dass das der Fall ist. Unterschiedliche STL-Impl bedeutet wegen der templates ja auch "unterschiedliche Schnittstelle"...

    Wenn Du von "char* ist üblich" sprichst, meinst Du damit aber, dass der "Empfänger" (=.exe) sich den Inhalt kopiert, bevor die DLL entladen wird oder dass der "Sender" (=.dll) in einen übergebenen Speicherbereich (des Empfängers) kopiert, stimmts ?
    IIRC möchte der OP hier einen Returnwert zurückgeben und da habe ich (bei char* und den aktuell beobachteten Problemen) gewisse Bedenken....

    Gruß,

    Simon2.



  • also ich habe bislang keine Probleme mit unterschiedlichen ÜEs gehabt,

    Stell mal bisserl an den compileroption's rum. besonders multihtread und singlethread einstellungen und die schalter, die das speicherverhalten des compilers beeinflussen. Gibt lustige effekte 🙂

    Und es gibt verschiedene Philosophien dahinter. Unter Linux z.b. ist das ganze nur halb so tragisch (auch da gibts probleme an und ab) weil es da einen systemcompiler gibt, und es auch meist globale compilerflags. Damit ist ne c++ schnittstelle meist binaerkompatibel, solange die keiner ueberschreibt (die flags). Ansonsten findet man immer so putzige Anmerkungen in den dokus das plugins mit gewissen flags uebersetzt werden muessen ....

    Unter windows gibts auch keinen systemcompiler.

    Und frameworks aus der linux welt habens da konzeptionell schwer.
    Wir haben unsere QT Dlls z.b. immer mit ins system32 verzeichniss gespielt. Unsere Tools ham die ja eh alle verwendet. Ging solange gut bis nen anderer Hersteller auch qt programme erstellt hat, mit der selben major version und anderen compilereinstellungen. Der installierte seine Dll's auch ins sysem32 verzeichnis ^^
    Tolle sache fuer den user, bei uns haeuften sich die anrufe: Seit wir tool XYZ verwenden, gehen eure Tools nicht mehr. Absturz, CTD ....

    nun verteilen wir für jedes Program die QT Dlls alle seperat ... nicht grad der Sinn einer DLL ^^

    Wenn Du von "char* ist üblich" sprichst, meinst Du damit aber

    Ich meinte damit, das es ueblich ist bei DLL schnittstellen flache unkomplizierte Datentypen zu verwenden, anstatt von ausdefinierten klassen.

    Ciao ...



  • Hi,

    ja - wie gesagt: Immer identisch kompiliert, dann klappt's auch. 😉

    Aber natürlich hast Du Recht: In der Praxis ist das bisweilen sehr schwer bzw. unmöglich.

    Gruß,

    Simon2.



  • Hm. In der Praxis ist das eigentlich ganz einfach... zumindest mit MSVC. Immer DLL Runtime verwenden, immer multithreaded, nie Debug und Release mischen -> fertig.

    BTW: Wenn bei std::string nur eine Adresse kopiert wird (also kein "deep copy") handelt es sich um eine nicht konforme COW Implementierung wie sie AFAIK z.B. der VC6 hat. Ab 7.1 sollte das gegessen sein. Andere Compiler = ich nix wissen 🙂

    In unserer Firma verwenden wir das im Übrigen andauernd, also STL Objekte (meist std::string/std::wstring aber auch manchmal std::vector etc.) über DLL Grenzen hinweg zu verwenden, und es gab bis jetzt noch keine Probleme. Ausser mal dass Debug und Release gemischt wurde. Das haben wir aber abgestellt indem die DLLs und EXEs einfach nen TAG im Namen tragen, also z.B. "-vc71-d.dll" oder ähnliches. Bei DLLs die debug/release "neutral" sind fällt das "-d" bzw. "-r" weg, bei DLLs die compiler "neutral" sind (also reine WIN32 DLLs) fällt das "-vcxx" weg und so fort.


Anmelden zum Antworten