MQL5 Der Compiler unterscheidet nicht zwischen einer Klasse und einem Zeiger auf sie - Seite 13

 
Ilya Malev:

Es ist in MCL einfach nicht dasselbe wie in C++. Hier ist ein Zeiger kein separater Datentyp, sondern beides sind Objekte, und eine Variable enthält ihren Handle.

oder?

// тот же класс А что был выше

A a; // будет создан автообъект с реальным выделением памяти и инициализацией. 'a' является указателем со статусом POINTER_AUTOMATIC

A* pA; // память под объект не выделена, объекта нет. pA является указателем со статусом POINTER_INVALID или POINTER_DYNAMIC?

Aber ich kann nicht mit Sicherheit sagen, welchen Status der Zeiger nach der Erstellung erhält:POINTER_INVALID oder POINTER_DYNAMIC. Theoretisch sollte es POINTER_INVALID sein, bis es die Adresse von new erhält.

 
Ilya Malev:

Das heißt, erklären Sie

Und Sie werden genau das gleiche "Auto-Objekt" haben, aber Sie müssen es selbst löschen.

Das ist nicht automatisch...

 
SemenTalonov:

Ich kann nicht sagen, welchen Status der Zeiger nach der Erstellung erhält,POINTER_INVALID oder POINTER_DYNAMIC. Eigentlich sollte es POINTER_INVALID sein, bis new die Adresse erhält.

Das ist richtig, der Status wird POINTER_INVALID sein. Die Variablen a und pA sind jedoch vom gleichen Typ. Nur a ist eine Konstante, der Konstruktor wird bei der Erstellung und der Destruktor beim Verlassen des Blocks aufgerufen, während auf pA zufällig zugegriffen wird und der Konstruktor und Destruktor willkürlich aufgerufen werden.

Eine Variable, die ohne * deklariert ist, kann ohne besondere Tricks nicht den Status POINTER_INVALID erhalten. Das stimmt auch, aber nicht, weil die Variablen von unterschiedlichem Typ sind, sondern weil der Compiler Konstruktor- und Destruktoraufrufe gut kontrolliert und es verbietet, einen anderen Wert zuzuweisen.

Und da Variablen im Wesentlichen vom gleichen Typ sind, gibt es keine Logik für den Zugriff auf Klassenmethoden über sie.

 
Ilya Malev:

Dies ist korrekt, der Status ist POINTER_INVALID. Die Variablen a und pA sind jedoch vom gleichen Typ. Nur a ist konstant und der Konstruktor wird bei der Erstellung und der Destruktor beim Verlassen des Blocks aufgerufen, und pA ist mit zufälligem Zugriff und mit zufälligen Konstruktor- und Destruktoraufrufen.

Der ganze Ärger kommt also nur daher, dass man sie unterscheiden muss. D.h. ein Zeiger erfordert eine verantwortungsvollere Haltung (dieDYNAMISCHE).

 
SemenTalonov:

Der einzige Grund für dieses Problem ist, dass sie unterschieden werden müssen. D.h. ein Zeiger erfordert eine verantwortungsvollere Haltung (dieDYNAMISCHE).

Meiner Meinung nach besteht der Sinn von OOP nur darin, dass Objektreferenzen übergeben und gespeichert werden können, und dass verschiedene Klassen mit unterschiedlichem Verhalten darin geschrieben werden können. Wenn man anfängt, einen Verweis auf ein "Auto-Objekt" zu speichern, ohne auch nur die Polymorphie zu berühren, verliert man bereits alle Unterscheidungsmerkmale (da es keine Benutzervariablen vom Typ A& gibt)

 
Ilya Malev:

Eine Variable, die ohne * deklariert ist, kann nicht ohne besondere Tricks den Status POINTER_INVALID erhalten. Das stimmt auch, aber nicht, weil die Variablen von unterschiedlichem Typ sind, sondern weil der Compiler Konstruktor- und Destruktoraufrufe gut kontrolliert und es verbietet, ihr einen anderen Wert zuzuweisen.

Ganz genau. Der Auto-Objekt-Zeiger wird seinen Status nicht ändern, während derPOINTER_DYNAMIC-Zeiger zu jedem Zeitpunkt der Programmausführung ungültig werden kann. Die Gründe sind nicht so wichtig wie die Möglichkeit eines solchen Ereignisses selbst.

 
SemenTalonov:

Ganz genau. Der Auto-Objekt-Zeiger wird seinen Status nicht ändern, während derPOINTER_DYNAMIC-Zeiger während der Programmausführung ungültig werden kann. Die Gründe sind nicht so wichtig wie die Möglichkeit eines solchen Ereignisses selbst.

Es gibt ein hervorragendes und sicheres Mittel dagegen:

class A{~A(){}};

void OnStart()
 {
  A*a=new A;
  delete a; // oops =))
 };
Nun, ich denke, Programmierer sollten die Lebenszeit von Objekten und die Zugriffsmöglichkeiten auf Variablen selbst im Auge behalten, während eine gut durchdachte Architektur Fehler ein oder zwei Jahre nach dem Schreiben des Codes minimieren wird...
 
Die Lebensdauer des Objekts muss nämlich mit der Lebensdauer von "Live"-Zeigern auf das Objekt übereinstimmen. Natürlich ist das dynamische Objekt POINTER_DYNAMIC auch nur eine halbe Lösung, die bei unüberlegtem Kodieren zu Problemen führt. Aber POINTER_AUTOMATIC gibt mir auch nicht die Skalierbarkeit, die ich brauche, um Objekte richtig zu behandeln. Wir brauchen es so: Wenn beim Verlassen des Blocks keine Zeiger auf das Objekt erstellt wurden, außer der Autovariablen, in der es erstellt wurde, dann wird das Objekt gelöscht. Wenn Referenzen außerhalb des aktuellen Blocks empfangen wurden - löschen Sie das Objekt nicht, solange diese Referenzen noch existieren. Dann ist die Skalierbarkeit gegeben und der Programmierer muss nicht ständig die Löschung selbst überwachen... (Wenn Sie jetzt z.B. A* a = new A; und dann wieder a = new A schreiben, geht das erste Objekt für immer verloren, und es ist garantiert, dass es beim Beenden des Programms zu Speicherverlusten in den Protokollen kommt. Und wo sieht der berühmte Code-Optimierer das?)
 
Ilya Malev:
Im Wesentlichen muss die Lebensdauer eines Objekts der Lebensdauer von "Live"-Zeigern auf das Objekt entsprechen. Natürlich ist das dynamische Objekt vom Typ mcl POINTER_DYNAMIC auch eine halbherzige Lösung, die Probleme verursacht, wenn das Coding nicht sehr effizient ist. Aber POINTER_AUTOMATIC gibt mir auch nicht die Skalierbarkeit, die ich brauche, um Objekte richtig zu behandeln. Wir brauchen es so: Wenn beim Verlassen des Blocks keine Zeiger auf das Objekt erstellt wurden, außer der Autovariablen, in der es erstellt wurde, dann wird das Objekt gelöscht. Wenn Referenzen außerhalb des aktuellen Blocks empfangen wurden - löschen Sie das Objekt nicht, solange diese Referenzen noch existieren. Dann ist die Skalierbarkeit gegeben und der Programmierer muss nicht ständig die Löschung selbst überwachen... (Wenn Sie jetzt z.B. A* a = new A; und dann wieder a = new A schreiben, geht das erste Objekt für immer verloren, und es ist garantiert, dass es beim Beenden des Programms zu Speicherverlusten in den Protokollen kommt. Und wo sieht der berühmte Code-Optimierer das?)

Das war auch eine ziemliche Überraschung. Schließlich kennt er genau jedes Byte, das entwichen ist, will es aber nicht freigeben. Also werden Dino-Zeiger im Moment gar nicht beobachtet? Er zählt einfach die Differenz zwischen angefordertem und freigegebenem Speicher.

Und Lebensdauer und leere/verlorene Zeiger sind nur eines der Probleme. Bevor wir die Probleme im Zusammenhang mit der impliziten Umwandlung von Zeigern in Objekte diskutiert, das ist, wo es ein Absturz ist) Wenn aus Versehen (zB der Compiler muss nicht erlaubt haben, um solche Code zu kompilieren), statt der erwarteten Zeiger können Sie eine Kopie eines Objekts durch Zeiger, die wiederum kann ins Leere zeigen zu erhalten). Nun, Sie selbst haben bereits über Vergleichsoperationen geschrieben. Auch dort ist alles sehr selbstverständlich.

 
SemenTalonov:

1. Das war auch eine ziemliche Überraschung. Schließlich kennt er genau jedes Byte, das entkommen ist, und will es nicht freigeben. Also werden Dino-Zeiger im Moment gar nicht beobachtet? Es wird lediglich die Differenz zwischen dem angeforderten und dem freigegebenen Speicherplatz gezählt.

Und Lebensdauer und leere/verlorene Zeiger sind nur eines der Probleme.

1. Nicht wirklich, das Schreiben einer einfachen GC für dynamische Objekte wäre ein Kinderspiel für Entwickler, aber sie haben diese Meldungen absichtlich hinterlassen, damit die Programmierer sehen können, dass sie einen Fehler in ihrem Programm haben. Weil ihre dynamischen Objekte so ein Semi-C# sind (ich bin kein Experte darin, aber von dem, was ich gehört habe) - als ob sich Objekte auf die gleiche Weise verhalten (keine Zeiger, aber alles sind Objekte), und kein ausgeklügeltes Subsystem für sie entwickelt wurde.

2. Nun, ja, natürlich, wenn Objektvariablen vom gleichen Typ wären (d.h. nicht automatisch oder unabhängig gelöscht würden, sondern durch den eingebauten Müllsammler, wenn es keine Referenzen auf sie gibt), dann wären alle Referenzen auf sie genau gleich.