Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?
-
Hallo,
bisher ging ich davon aus, dass der allgemein übliche (und anscheinend einzige dokumentierte) Weg, ref-Klassen zu verwenden, über ein Handle und gcnew führt. Beispiel:
using namespace System::Windows::Forms; [System::STAThreadAttribute] int main (cli::array <System::String ^> ^ args) { Form ^ MainFormInstance = gcnew Form; // Verwaltete Klasse (ref class) auf dem GC-Heap anlegen Application::Run (MainFormInstance); return 0; }
Jetzt hat ein Kollege aber ref-Instanzen als einfache Variable deklariert - und das funktioniert überraschenderweise:
Form MainFormInstance; // einfache Variable einer Ref-Klassse Application::Run (%MainFormInstance);
In meinem Verständnis legt man hier also eine verwaltete Klasse auf dem normalen C++-Stack an, nicht wie "im Sinne des Erfinders" auf dem GC-Heap... Deshalb hätte ich auch eine Fehlermeldung vom Compiler (ich verwende VS 2012) erwartet - aber es kommt nicht mal eine Warnung. Das Programm läuft auch normal.
Ist diese Form der Verwendung von verwalteten Klassen wirklich korrekt? Schließlich instanziiert sämtlicher C++/CLI-Code, den ich bisher gesehen habe, als auch alle MS-Dokus Ref-Klassen ausschließlich per gcnew. Ist der Compiler hier zu tolerant, oder kann man die zweite Variante ohne gcnew auch bedenkenlos nutzen?
Viele Grüße
Lutex
-
-
Danke! Das scheint mir aber recht fragwürdig, wenn sich dahinter nach wie vor ein verwaltetes Handle verbirgt und der Compiler das so verschleiert. Muss morgen mal testen, was da bei Zuweisungen "Instance1 = Instance2" passiert...
-
@lutex sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Muss morgen mal testen, was da bei Zuweisungen "Instance1 = Instance2" passiert...
Das, was in Deinem
operator=()
steht?
-
@lutex
Das ist äußerst bequem, weil Du Dich nicht um FInalizer und Cleanup küpmmern musst falls IDispable eingesetzt wird.Eine Zuweisung ist natürlich so nicht möglich. Das ist eben kein Handle mehr.
Intern verbirgt C++/CLI das ganze gcnew Geraffel ink. abräumen mit delete.Ich benutze das sehr oft.
-
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Eine Zuweisung ist natürlich so nicht möglich.
??
-
??
Eine ref class hat weder einen copy Konstruktor noch einen copy operator, oder was fragst Du?
Ein Assignment ist grundsätzlich nicht möglich. Passt weder zu .NET noch zu C++/CLI...
Oder auf was bezieht sich dein ???
-
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Eine ref class hat weder einen copy Konstruktor noch einen copy operator, oder was fragst Du?
Ist aber nicht so, daß man keinen Zuweisungsoperator implementieren könnte?
-
@swordfish sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Eine ref class hat weder einen copy Konstruktor noch einen copy operator, oder was fragst Du?
Ist aber nicht so, daß man keinen Zuweisungsoperator implementieren könnte?
Nein. Kann man natürlich nicht. Das wäre so was wie ein Clone und Du musst das über eigene Funktionen abdecken.
So etwas mach mit .NET keinen Sinn...
-
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Nein. Kann man natürlich nicht.
using namespace System; ref struct foo { int bar; foo(int bar) : bar{ bar } {}; void operator=(foo % f) { bar = f.bar; } }; int main() { foo f{ 42 }; foo g{ 5 }; Console::WriteLine(f.bar); Console::WriteLine(g.bar); f = g; Console::WriteLine(f.bar); Console::WriteLine(g.bar); }
???
-
@martin-richter
Doch, man kann einen Zuweisungsoperator implementieren. Hab's grad ausprobiert; folgendes läuft unter VS 2012:public ref class TestPoint { public: int X, Y; TestPoint ^ operator = (const TestPoint % OtherPoint) { X = OtherPoint.X; Y = OtherPoint.Y; return this; } }; int main (cli::array <System::String ^> ^ args) { TestPoint A, B; A.X = 10; A.Y = 20; B.X = 30; B.Y = 40; B = A; System::Console::WriteLine ("A=({0};{1}) B=({2};{3})", A.X, A.Y, B.X, B.Y); System::Console::ReadKey(); }
Die Ausschrift lautet ohne die Zuweisung B=A:
A=(10;20) B=(30;40)
und mit der Zuweisung:
A=(10;20) B=(10;20)
-
@lutex
Stimmt. Das geht allerdings nur über eine Tracking Refrenz. Nicht über ein Handle...
-
@swordfish sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Nein. Kann man natürlich nicht.
???
Du hast einen ref struct also einen Value Type erzeugt. Der ist kopierbar. Aber eben nicht ein ref class!
class und struct sind in C++/CLI was ganz anderes. als in C++. Einmal eben ein Referenz-Typ und einmal eine Value-Type.
-
@lutex sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
TestPoint A, B;
Schon mit
TestPoint A, ^B;
Hast Du einen komplett anderen Syntax und musst den Ref Typ in eine Tracking Referenz umwandeln.
-
Ehe wir jetzt endlos weiterdiskutieren:
SORRY ich habe mich zu ungenau ausgedrückt und die expliziten Unterschiede zwischen Tracking References und den Objekt Referenzen nicht korrekt erklärt. Auch was es hier mit den entsprechenden Copy Operatoren auf sich hat.
Und bei dem Wetter habe ich keinen Bock auf Haarspalterei...
BTW: Tracking References gibt es nur in C++/CLI und in keiner anderen .NET Sprache
Siehe SO
-
@martin-richter sagte in Wieso lassen sich ref-Instanzen wie einfache Variablen deklarieren?:
Du hast einen ref struct also einen Value Type erzeugt. Der ist kopierbar. Aber eben nicht ein ref class!
C++/CLI standard - Ecma International sagte:
12.1 Value types
[...] Value classes are declared with the value class or value struct keywords.C++/CLI standard - Ecma International sagte:
21.1 Ref class definitions
A ref class is a class defined with the class-key ref class or ref struct.
A ref class definition and ref struct definition differ in the default accessibility of members; by default, the members of a ref class are private, while those of a ref struct are public.using namespace System; ref class foo { public: int bar; foo(int bar) : bar{ bar } {}; void operator=(foo % f) { bar = f.bar; } }; int main() { foo f{ 42 }; foo g{ 5 }; Console::WriteLine(f.bar); Console::WriteLine(g.bar); f = g; Console::WriteLine(f.bar); Console::WriteLine(g.bar); }
<°)))<> ??
[read: not sure if trolling or just in grandpa-mode.]
-
@swordfish
Und recht hast Du, ehe ich noch mehr Schwachsinn von mir gebe schweige ich jetzt,..
-
Bitte Martin, geh in den Schatten, trink viel, streng Dich nicht an ... alte Leute sind ganz besonders anfällig für Hitzeschläge!! :face_with_stuck-out_tongue_winking_eye:
-
Naja die Unterschiede zwischen C# und C++/CLI sind manchmal schon etwas verwirrend. Also so Sachen wie
struct
vs.class
(egal bei C++/CLI, wichtig bei C#) oder die Bedeutung von~ClassName()
.Da kann man sich schonmal vertun.
Wobei IMO beides bei C# 1.0 verbockt wurde -- auch wenn vielleicht nicht absehbar war dass es jemals sowas wie C++/CLI geben könnte.