Tracking Reference auf Object => Handle geht verloren
-
Hallo,
ich habe ein Problem mit Tracking Referenzen, z.B. bei folgender Funktion:
void func (String ^% d, Object ^% c) { c = gcnew String ("new string 1"); d = gcnew String ("new string 2"); }
Wenn ich diese Funktion wie folgt aufrufe, ...
String^ a = "old string 1"; String^ b = "old string 2"; func (a, b);
... haben nachher meine Variablen a und b folgende Werte:
a: "new string 1"
b: "old string 2"Der Parameter a verhält sich wie gewünscht, während zwischen b und d die Referenz verloren geht, wahrscheinlich durch den Cast von String auf Object.
Ich wüsste nun gerne, was da unter der Haube genau passiert und wie man trotzdem ein call-by-reference mit Object-Typen hinbekommt.Bislang mache ich es statt wie oben so:
Object^ b = "old string 2";
Dann geht das Handle nicht verloren, es ist aber nicht gerade schön...
Gruß,
Holger
-
Guten Morgen,
Ich finde den Fall bemerkenswert interessant und kann ihn reproduzieren. Klären kann man ihn sehr gut indem man sich den IL-Code genau anschaut:.method assembly static void func(string& d, object& c) cil managed { .maxstack 2 L_0000: ldarg.1 L_0001: ldstr "new string 1" L_0006: stind.ref L_0007: ldarg.0 L_0008: ldstr "new string 2" L_000d: stind.ref L_000e: ret } .method assembly static int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) main() cil managed { .maxstack 3 .locals ( [0] string b, [1] string a, [2] int32 num, [3] object obj2) L_0000: ldc.i4.0 L_0001: stloc.2 L_0002: ldnull L_0003: stloc.1 L_0004: ldnull L_0005: stloc.0 L_0006: ldstr "old string 1" L_000b: stloc.1 L_000c: ldstr "old string 2" L_0011: stloc.0 L_0012: ldloc.0 L_0013: stloc.3 L_0014: ldloca.s a L_0016: ldloca.s obj2 L_0018: call void <Module>::func(string&, object&) L_001d: ldstr "{0}\n{1}" L_0022: ldloc.1 L_0023: ldloc.0 L_0024: call void [mscorlib]System.Console::WriteLine(string, object, object) L_0029: ldc.i4.0 L_002a: stloc.2 L_002b: ldloc.2 L_002c: ret }
Meine Analyse: Bei main/L_0011 speicherst du die Referenz auf den konstanten "old string 2" in b (stloc.0), nachher wird dieselbe Referenz mit stloc.3, siehe L_0013, in einem temporären Feld gespeichert. Vor dem Aufruf der Funktion wird bei L_0016 mittels ldloca.s die Adresse des temporären Feldes auf den Stack geladen; konsequenterweise wird daher bei func/L_000d (stind.ref) auch nur das temporäre Feld überschrieben. Bei der Ausgabe der Strings wird jedoch wieder der ursprüngliche String geladen (L_0023, ldloc.0). Ich glaube nicht, dass dieses Verhalten vom Compilerhersteller gewünscht war. Es ist vermutlich ein Bug oder so, melde es doch mal
Viel Vergnügen noch