Rückgabe Variant
-
Hallo _cu hallo Belli, danke für eure konkrete Hilfe
Meine Variants beinhalten ausser int, double, float, auch BStr.
Der macht mir dann auch am meisten Sorgen.Um auf Nummer sicher zu gehen würde ich am liebesten immer VariantCopy verwenden.
Mein Problem ist hier aber der Rückgabewert.Wenn ich einen VARIANT zurückgebe ist dies eine Kopie ohne VariantCopy
Hier nochmals ein Beispiel mit CString
virtual VARIANT GetVariantValue() const
{
VARIANT variant;
VariantInit(&variant);variant.vt = m_varianttype;
CString csvalue = Value;
variant.bstrVal = csvalue.AllocSysString();return variant;
}Wann muss ich hier VariantClear aufrufen?
-
VariantClear musst Du anwenden, wenn Du Deinen VARIANT nicht mehr brauchst.
Eigentlich ist immer der verantwortlich, der ein VARIANT erhält.Einfacher ist die Verwendung von CComVariant (oder COleVariant). Die kapseln das für Dich.
Dann geht auch die Initialisierung "wie von selbst"
Solchen Code halte ich für nicht gut.
variant.vt = m_varianttype; CString csvalue = Value; variant.bstrVal = csvalue.AllocSysString();
Wenn Du schon klar einen VT_BSTR zuweist, dann solltest Du auch VT_BSTR direkt setzen. Und höchstens vorher noch einen ASSERT Test machen.
ASSERT(m_varianttype==VT_BSTR);
Bitte verwende Codetags.
-
Hi Martin
VariantClear musst Du anwenden, wenn Du Deinen VARIANT nicht mehr brauchst.
Eigentlich ist immer der verantwortlich, der ein VARIANT erhält.Also auserhalb dieser Funktion!
Die Eigentliche Frage ist was passiert wenn ich einen VARIANT zurückgebe ist das dann eine Kopie. Was ist der Unterschied wenn ich VariantCopy mache?
Einfacher ist die Verwendung von CComVariant (oder COleVariant). Die kapseln das für Dich.
Jo. Das Problem ist dass ich ODK Funktionen von WinCC (Siemens) verwende und deren Schnittstelle ist nun mal VARIANT sonst hätte ich diesen Datentyp gar nicht verwendet.
Solchen Code halte ich für nicht gut.
Hier wiederum das Problem dass ich einen CString erhalte und diesen muss ich an die Schnittstelle als VARIANT weiterleiten.
Bitte verwende Codetags.
Sorry. Klar mache ich (fast) immer. Hatte es zuspät bemerkt.
-
Oh.
Wenn Du schon klar einen VT_BSTR zuweist, dann solltest Du auch VT_BSTR direkt setzen. Und höchstens vorher noch einen ASSERT Test machen.
Jetzt habe ich das erst verstanden! m_varianttype ist immer VT_BSTR.
Dachte du meinst ich soll keinen CString verwenden. Habe nicht genau gelesen sorry.
-
Nochmals kurz zu dem Rückgabewert VARIANT
Wenn nun der VARIANT nun ein Member meiner Klasse ist und ich gebe diesen als Kopie zurück muss ich dann VariantClear ausserhalb aufrufen und auch VariantClear im Destruktor meiner Klasse.
Wie verhält sich das ganze wenn ich eine konstante Referenz des VARIANTS zurückgebe?
-
Da VARIANT keinen eigenen Destruktor hat, musst Du jeden VARIANT genau einmal via VariantClear zerstören, damit seine Ressourcen freigegeben werden.
Immer vorausgesetzt, er belegt überhaupt welche, siehe vorherige Posts.
Wenn Du einen VARIANT durch einfache Zuweisung oder Rückgabe aus einer Funktion, wie der TE, erhalten hast, darfst Du den maximal einmal zerstören, weil keine tiefe Kopie erstellt worden ist.
Wenn Du einen mit VariantCopy kopiert hast, hast Du eine tiefe Kopie erstellt, und musst zu gegebener Zeit beide, Quelle und Ziel, zerstören.
-
Und bei Rückgabe als Referenz verhält es sich wie mit einer Kopie
-
Was muss ich machen dass VariantClear nicht zum Absturz meines Programmes führt.
Gibts da ne Überprüfung "Variant bereits gelöscht?", oder kann ich eine Exception abfangen?
-
VariantCLear führt dann zum Absturz, wenn Du einen Speicher zum Beispiel zweimal freigibst.
VARIANT var1, var2; var1.vt = VT_BSTR; var1.bstrVal = anystr.AllocSysString(); var2 = var1; VariantClear(&var1); // Crash! VariantClear(&var2);
Ist doch logisch.
Arbeite mit CComVariant und Du hast die Probleme nicht.
Und solche Exceptions kann man nicht abfangen und sie dann vor allem korrekt behandeln...
Selbst wenn andere ein VARIANT verwenden, so doch eher VARIANT*! Und hier ist die Behandlung transparent... und selbst wenn nicht. Kannst Du ja jederzeit aus einem CComVariant eine Kopie erzeugen.!
-
Ist doch logisch.
Ja in dem einfachen Beispiel schon.
Mein Programm besser gesagt meine DLL stürzt ab und zu ab. Ich kann aber nicht lokalisieren wo.
Selbst wenn andere ein VARIANT verwenden, so doch eher VARIANT*!
Was meinst du mit "so doch eher VARIANT*"
-
Zeiger auf einen Variant.
Debugge doch. Wenn es crashed kannst Du doch die Codestelle ausmachen.
-
Zeiger auf einen Variant.
Das ist klar
Selbst wenn andere ein VARIANT verwenden, so doch eher VARIANT*!
Du meinst ich soll einen Zeiger auf Variant verwenden?
Debugge doch. Wenn es crashed kannst Du doch die Codestelle ausmachen.
Schön wärs. Ich kompiliere eine DLL diese stellt Exportfunktionen bereit die wiederum von WinCC (script.exe) verwendet werden.
Um nun mein Programm debuggen zu können muss ich mich an den Prozess anhängen.
Stürzt nun das Programmm ab bleibe ich sehr wohl mit dem Debugger hängen. Der besitzt aber einen Aufrufstack der nichts mit meiner DLL zu tun hat.Da liegt jetzt die Annahme nahe dass es nichts mit meiner DLL zu tun hat. Verwende ich nun aber eine Vorgängerversion meiner DLL aus dem Repository führt es nicht zu einem Absturz.
Vergleiche ich nun die beiden Versionen im Repository sind hier nur Änderungen im Code mit dem Handling der VARIANTS zu verzeichnen.
Ich hatte an 4 Stellen VariantClear hinzugefügt weil wir über einen längeren Zeitraum einen Speicheranstieg zu verzeichnen hatten. Dieser ist nun nach dem einfügen von VariantClear weg.
Dafür stürzt das Programm ab. Leider aber nur sehr unregelmässig.
Debuggen bringt mich leider nicht weiter.
-
Dann wird
VariantClear()
wohl mehrmals für den selbenVARIANT
aufgerufen bzw. für mehrere, die die selben Ressourcen halten.
-
Wenn der Heap zerstört wird, dann kann der Crash auftreten wann auch immer das eben entdeckt wird.
Und dennoch kann man das Debuggen.Einfach nur VariantClear einstreuen ist nicht sonderlich intelligent.
Die Frage ist wem, der VARIANT gehört.
-
Wenn der Heap zerstört wird, dann kann der Crash auftreten wann auch immer das eben entdeckt wird. Und dennoch kann man das Debuggen.
Ok und wie. Ich schalte alle Exceptions ein habe an allen VariantClear ein Breakpoint gesetzt. Lieder habe ich ein paar HundertInstanzen. Stichprobenmässig sind die VariantClear alle in Ordnung.
Einfach nur VariantClear einstreuen ist nicht sonderlich intelligent.
Wer sagt den das die irgendwo eingestreut wurden.
Ich habe mir schon was dabei gedacht. Bin nun auf Fehlersuche und habe mich nun nochmals versichert dass ich mit den Variants alles richtig verstanden habe. Oder halt doch noch nen bug drin habe.
Mag sein dass ich vieleicht einmal zu viel VariantClear aufgerufen habe. Aber das will ich ja nun finden.
Wie kann man den davon ausgehen, nur weil man auf der Suche nach einem Fehler ist das man das was man gemacht hat einfach nur willkürlich ist???
-
Starte die Script.exe im Debugger. Dadurch wird der Debug-Heap aktiv. Das sollte direkt zu einem Stop führen wenn der Heap zerstört wird.
-
Man kann die Script.exe nicht im Debugger starten, mir ist zumindest nicht bekannt wie.
Ich weiß nicht ob du WinCC von Siemens kennst. Das ist eine Applikation für die Visualisierung im Bereich der Automatisierung.
In diesem WinCC lässt sich C programmieren. Um irgendwelche koplexeren Aufgaben zu erledigen schreiben wir eigene C++ Dll's deren Exportfunktionen sich wiederum in diesem sogenannten c-script aufrufen lassen.
Diese Script.exe wird von WinCC gestartet und fürt dann das ganze aus.
Der Editor ist ziemlich rudimentär. Er bietet auch keinen Debugger.
Wenn irgendeine DLL eine Exception wirft stürzt die script.exe ab und das wars dann.
Ich habe bisher nur die Möglichkleit gefunden, die debug Version meiner DLL abzulegen und mich mit Visual Studio an die Script.exe anzuhängen. Bisher habe ich so immer zuverlässig meine Fehler gefunden.
Nur in diesem Fall lande ich irgendwo im Nirvana.
-
siehe http://stackoverflow.com/questions/1010106/how-to-debug-heap-corruption-errors
insbesondere die 2te Antwort zum Thema PageHeap via gflags.exe
-
Hallo
Danke euch ihr habt mir schon ein ganzes Stück weitergeholfen.
Noch ne weitere Frage:
VARIANT var1; var1.vt = VT_BSTR; var1.bstrVal = anystr.AllocSysString();
reicht es hier VariantClear(&var1) aufzurufen.
oder muss ich auch noch SysFreeString(var1.bstrVal); aufrufen
-
Eines von beiden musst Du aufrufen. VariantClear ist normalerweise das Mittel der Wahl, weil Du dann nicht selbst nachhalten musst, was überhaupt in Deiner Variablen drin ist.
VariantClear kümmert sich dann auch um die Freigabe des bstrVal. Du kannst den natürlich auch selbst freigeben, und Dir dann VariantClear sparen ...