Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Nutzungsmöglichkeiten und Vorschläge - Seite 19
Sie verpassen Handelsmöglichkeiten:
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Registrierung
Einloggen
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Wenn Sie kein Benutzerkonto haben, registrieren Sie sich
Sie können ja Ihre eigene Spezialisierung einer Funktion für eine Klasse schreiben.
Ohne eine Schnittstelle geht es nicht.
Ohne eine Schnittstelle geht es nicht.
Sie können es nicht ohne eine Schnittstelle tun? )
Nun, denken Sie darüber nach. Wie dem auch sei, bringen Sie den Thread nicht durcheinander, bitte.
Problem
Offensichtlich kann GetHashCode in der MQL5-Benutzerumgebung nicht richtig implementiert werden. Dies liegt daran, dass nicht auf alle Objekte zugegriffen werden kann. Und wenn die Implementierung für primitive Mitglieder wie double int usw. gut funktioniert, wird der Hash für komplexe Objekte (Klassen, Strukturen und sogar Aufzählungen) nach Namen berechnet. Wenn wir Tausende von CObjects oder sogar ENUM_something_that haben, dann werden CHashMap und CHashSet zu LinkedList degenerieren:
Dies lässt sich nicht vermeiden, da wir auf der Benutzerebene nur den Namen des Objekts kennen:
Daher sind die Hashes aller Objekte komplexer Typen einander gleich, und dieser Suchcode hier beinhaltet eine vollständige Array-Aufzählung:
Dies ist sogar so wichtig, dass es den ganzen Sinn der Verwendung von Generic an der Wurzel aufhebt. Der Punkt ist, dass Sie in den meisten Fällen komplexe Objekte assoziieren oder speichern müssen: Aufzählungen, Strukturen oder Klassen. Wenn Sie mit einfachen Typen arbeiten müssen, können Sie auch mit etwas Einfacherem arbeiten.
Damit generische Sammlungen korrekt mit Klassenobjekten funktionieren, müssen diese Klassen die Schnittstelle IEqualityComparable implementieren, in der die Methoden Equals und HashCode definiert sind. Das bedeutet, dass der Benutzer die Methoden zur Berechnung der Hash-Codes selbst festlegen muss, und das ist bisher die einzige Möglichkeit, da es unmöglich ist, diese Methoden automatisch zu implementieren, wie es beispielsweise in .Net mit MQL5 geschieht.
Damit generische Sammlungen korrekt mit Klassenobjekten funktionieren, müssen diese Klassen die Schnittstelle IEqualityComparable implementieren, in der die Methoden Equals und HashCode definiert sind. Das bedeutet, dass der Benutzer Berechnungsmethoden für Hash-Codes festlegen muss, und das ist bisher die einzige Möglichkeit, da es unmöglich ist, diese Methoden automatisch zu implementieren, wie es beispielsweise in .Net mit Hilfe von MQL5 gemacht wurde.
Roman, du hast vergessen zu erwähnen, dass in MQL5 hat keine Schnittstellen. In diesem Artikel wird das Konzept der Schnittstellen in MQL5 vorgestellt.
p.s. Aber selbst wenn Schnittstellen in MQL5 erscheinen würden, würde das Problem mit Strukturen und Aufzählungen ungelöst bleiben.
Roman, du hast vergessen zu erwähnen, dass in MQL5 hat keine Schnittstellen. Jede Diskussion über Schnittstellen im heutigen MQL5 ist eine böswillige Unterstellung und Demagogie.
p.s. Aber selbst wenn Schnittstellen in MQL5 erschienen wären, wäre das Problem mit Strukturen und Aufzählungen ungelöst geblieben.
Im Moment kann man in MQL5 im Prinzip keine Template-Methoden schreiben, die gleichzeitig für Klassen, Strukturen und Aufzählungen funktionieren würden, wegen der Besonderheiten der Datenübertragung.
Das ist es, wovon ich spreche. Aber die MQL5-Umgebung weiß alles über ihre Objekte! Es hat Zeiger auf Objekte und kennt alle Bezeichner von Enums (EnumToString). Deshalb brauchen wir GetHashCode als System- und Allesfresser-Funktion.
Erlauben Sie außerdem endlich die Vererbung mehrerer Schnittstellen. Schreiben Sie Generic für normale Schnittstellen um, und Sie haben einen Sweet Spot.
Die Situation ist offensichtlich: MQ-Entwickler wurden so oft durch Mehrfachvererbung in C++ verbrannt, dass sie nun jede Manifestation davon fürchten. Infolgedessen wird vorgeschlagen, einen Mist (Mehrfachvererbung) durch einen anderen Mist zu vermeiden: lächerliche Vererbungsketten.
Sie müssen verstehen, dass Schnittstellen nichts mit Vererbung zu tun haben. Eine Schnittstelle ist eine Erklärung, die eine Klasse verpflichtet, eine bestimmte Funktionalität bereitzustellen. Wenn zwei Klassen die gleiche Funktionalität implementieren, sollten sie nicht voneinander erben. Vererbung = böse.
Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien
Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Besonderheiten der Nutzung und Vorschläge
Roman Konopelko, 2017.12.18 16:29
1) Der Volumenwachstumsfaktor (Kapazität) ist nicht gleich 1,2, die Methode CPrimeGenerator::ExpandPrime wird zur Berechnung des neuen Volumens in CHashMap verwendet:
Bei dieser Methode wird die alte Sammlungsgröße mit zwei multipliziert, dann wird für den resultierenden Wert die nächstgelegene von der obersten Primzahl gefunden und als neues Volumen zurückgegeben.
Was den Anfangswert der Kapazität betrifft, so stimme ich zu, dass er sehr gering ist.
Andererseits gibt es immer Konstruktoren, bei denen man die Anfangskapazität explizit angeben kann:
Ich sehe also nicht viel Sinn darin, hier etwas zu ändern.
Ja, ich habe mich geirrt, ich bereue es.
Der Volumensteigerungsfaktor (Kapazität) für die CHashMap beträgt tatsächlich mehr als 2.
Ich danke für den Hinweis auf den Fehler und entschuldige mich für die Zeitverschwendung.
Andererseits habe ich es geschafft, mir Zeit zu nehmen, um die Implementierung von CPrimeGenerator zu studieren.
Und es gibt ein paar Vorschläge, vor allem zur Verbesserung der Leistung.
1. Beseitigen Sie zweideutiges Verhalten:
Wenn wir "INT_MAX - 10" als Parameter an CPrimeGenerator::ExpandPrime übergeben, wird das Ergebnis "INT_MAX" zurückgegeben.
Wenn wir "INT_MAX - 10" als Parameter an CPrimeGenerator::GetPrime übergeben, wird das gleiche Ergebnis zurückgegeben: "INT_MAX - 10".
Außerdem ist in beiden Fällen der zurückgegebene Wert keine Primzahl, was den Benutzer in die Irre führt.
2. Beim Aufruf vonGetPrime für Zahlen größer als7199369 wird die Speicherplatzersparnis zur Priorität, aber das rechtfertigt nicht die relativ schlechte Leistung und die unnützen Berechnungen.
Anregung:
- einen Vergleich der Zahl mit dem letzten Wert des ArraysCPrimeGenerator::s_primes[] hinzufügen und keine unnötige Aufzählung aller 72 Arrayelemente durchführen.
- Ersetzen der dynamischen Suche nach einfachen Zahlen (geht durch alle Zahlen in einer Reihe) durch ein Array von vordefinierten Werten wieCPrimeGenerator::s_primes[], aber mit linearer, nicht quadratischer, Steigerung.
Das Inkrement der Werte wird etwa 1 Million betragen (eine Zahl, die dem Inkrement von s_primes bei den letzten Elementen des Arrays entspricht).
Die Anzahl der Elemente kann bis zu 3000 betragen, die Werte reichen von 8M bis INT_MAX.
Das Array wird durch eine binäre Suche mit oberer Grenze durchsucht, die Anzahl der erforderlichen Iterationen beträgt 12.
3. WennGetPrime für Zahlen kleiner als7199369 aufgerufen wird, ist der schlimmste Fall eine lineare Suche über alle 72 Werte des ArraysCPrimeGenerator::s_primes[].
Die Anregung lautet:
- die Anzahl der Elemente im Array auf 70 reduzieren. (durch Streichen der ersten beiden oder der ersten und der letzten):
- wenn der Eingabewert kleiner oder gleich dem 6. Wert im neuen ArrayCPrimeGenerator::s_primes ist - dann werden die Zahlen linear durchlaufen (bis zu 6 Vergleiche).
- Andernfalls verwenden Sie die obere Grenze der binären Suche zwischen dem 7. und 70.
Die Idee ist, die lineare Suche nur so lange zu verwenden, wie es keine Leistungseinbußen im Vergleich zur binären Suche gibt.
Die vorgeschlagene Anzahl der Elemente - 6 - wird als Beispiel verwendet, in Wirklichkeit hängt alles von der konkreten Implementierung der binären Suche mit oberen Grenzen ab.
Der allgemeine Leistungsgewinn aufgrund der geringen Aufrufintensität einer bestimmten Funktion ist möglicherweise nicht so vorteilhaft, dass es sich lohnt, an der Verbesserung dieser Funktion zu arbeiten.