Komponentenmanipulation über Index
-
akari schrieb:
Du übersiehst zwei Sachen :
- Auch die Ermittlung des ClassName sowie der AnsiString-Vergleich mit "TEdit" braucht seine Verarbeitung.Ok, und was ist aufwendiger? Das oder dynamic_cast?
akari schrieb:
- Wenn du schon auf ClassName vergleichst, brauchst du auch kein dynamic_cast sondern dann reicht ein static_cast ohne Überprüfung.
Kannst du das bitte nochmal anders (und evtl ausführlicher) formulieren? Ich steh' schon wieder auf der Leitung!

Braunstein schrieb:
Wenn mans genau nimmt sollte auch bei der CheckBox-Umwandlung ein Test rein.
Aber die Ereignisbehandlung ist doch für CheckBoxClick; Sender ist doch immer ein TCheckBox-Element
Wozu der Test 
-
Hallo
Ok, und was ist aufwendiger? Das oder dynamic_cast?
Gute Frage. Schwer zu sagen. Ich vermute die ClassName-Variante.
Kannst du das bitte nochmal anders (und evtl ausführlicher) formulieren? Ich steh' schon wieder auf der Leitung!
Du machst momentan erst die ClassName-Überprüfung und dann die dynamic_cast-Umwandlung mitsamt Überprüfung. Damit ist eine Überprüfung doppelt. Und darum reicht eigentlich ein dynamic_cast aus.
Du kannst natürlich auch die ClassName-Überprüfung machen und statt dem dynamic_cast einfach static_cast verwenden. Denn static_cast ist nur eine Umwandlung ohne Überprüfung, die man nehmen darf wenn man sich wirklich sicher ist. Dafür ist static_cast zur Laufzeit kostenlos.Aber die Ereignisbehandlung ist doch für CheckBoxClick; Sender ist doch immer ein TCheckBox-Element
Braunstein meint genau das was ich oben gesagt habe : dynamic_cast brauchst du nur wenn du dir nicht sicher bist und ein Überprüfung braucht, ob die Umwandlung wirklich machbar ist. Das bedeutet aber auch das nach jedem sinnvollen dynamic_cast auch das Ergebnis von dynamic_cast überprüft werden sollte.
Wenn du dir zur Entwurfszeit sicher bist das es funktioniert dann reicht ein static_cast.
bis bald
akari
-
Kolumbus schrieb:
[Aber die Ereignisbehandlung ist doch für CheckBoxClick;
Die ist nur dafür gedacht. Ja. Wenn du sie aber mal versehentlich einem TEditClick zuweist knallt es. Dazu brauchst du nur mal im Objektinspektor falsch auswählen.
-
Hallo
Braunstein schrieb:
Kolumbus schrieb:
[Aber die Ereignisbehandlung ist doch für CheckBoxClick;
Die ist nur dafür gedacht. Ja. Wenn du sie aber mal versehentlich einem TEditClick zuweist knallt es. Dazu brauchst du nur mal im Objektinspektor falsch auswählen.
Also nur wegen dieser Befürchtung würde ich kein dynamic_cast verwenden. Soviel Kontrolle hab ich schon über mein Projekt

bis bald
akari
-
Mag sein. Ich finde es nur eine nützliche Angewohnheit, bei dynamic_cast grundsätzlich zu prüfen. Kann sein das das manchmal unnötig ist, aber auf keinen Fall fehlerhaft.

Wie du ja schon gesagt hast kann man ja sonst gleich static_cast nehmen.
-
Hallo
Braunstein schrieb:
Mag sein. Ich finde es nur eine nützliche Angewohnheit, bei dynamic_cast grundsätzlich zu prüfen. Kann sein das das manchmal unnötig ist, aber auf keinen Fall fehlerhaft.

Genau

Wie du ja schon gesagt hast kann man ja sonst gleich static_cast nehmen.
Und genau das würde ich in diesem Fall auch machen.
bis bald
akari
-
So, jetzt würde ich gern einen ausgeben; Ihr seid spitze - ich glaub' ich hab's gerafft!

Nach Abwägung eurer Argumente sieht das (vorläufige) Ergebnis nun so aus:void __fastcall TForm4::CheckBoxClick(TObject *Sender) { unsigned short j= static_cast<TCheckBox*>(Sender)->Tag; for(unsigned short k= 0; k < (this->ComponentCount-1); k++) { if((this->Components[k]->ClassNameIs("TEdit")) && (static_cast<TEdit*>(this->Components[k])->Tag==j)) { TEdit *VirtualEdit= static_cast<TEdit*>(this->Components[k]); if(!VirtualEdit->Enabled) VirtualEdit->Enabled= true; else { VirtualEdit->Enabled= false; VirtualEdit->Text= "0"; } break; } } } //---------------------------------------------------------------------------
-
Eine kleine Änderung
for(unsigned short k= 0; k < (ComponentCount-1); k++) { TEdit* VirtualEdit = dynamic_cast<TEdit*>(Components[k]); if(VirtualEdit && VirtualEdit->Tag==j) { if(!VirtualEdit->Enabled) VirtualEdit->Enabled= true; else { VirtualEdit->Enabled= false; VirtualEdit->Text= "0"; } break; } }
-
Ok, das this spare ich mir gerne. Ich weiß ja zur Entwicklungszeit wo ich mich bewege.

Das deine Version übersichtlicher ist gebe ich zu und sie entspricht ja auch deinen dargelegten Prinzipien, aber ist sie zur Laufzeit ressourcensparender? Du castest jede Komponente, ich überprüfe bei jeder den Namen... wie bekommen wir raus, was günstiger ist? Gibts da eine Möglichkeit?
-
dynamic_cast wie auch ClassNameIs sollten ähnliche Laufzeiten haben, so dass sich beide Versionen nicht viel nehmen. Sie müssen ja beide intern überprüfen welche Klasse wirklich hinter dem Object-Zeiger steckt. Wenn du es genau wissen willst mußt du es halt mal überprüfen.
-
Jetzt habe ich das mal getestet.
Die dynamic_cast Variante ist deutlich schneller als ClassNameIs (mehr als Faktor 20).
-
Interessant. Ich werd das morgen auch mal prüfen. Ich stell' mir vor, einfach nen Timer vorher zu starten und hinterher abzulesen. Passt das? Oder geht das so nicht?
Edit: immer diese Schreibfehler

Edit2: Schneller ist aber nicht unbedingt ressourcensparender (- CPU-Belastung, Arbeitsspeicher)?

-
Ich habe den Thread nur überflogen, daher ganz bescheiden die Frage: ist es möglich, daß eine TCheckListBox deine Bedürftnisse besser erfüllt?
-
Guten Morgen,
Danke für den Hinweis audacia. Da ich die Liste der fertigen Komponenten noch nicht so aus dem FF kenne (wie wohl die meisten Anfänger), war der prinzipiell gut. Ich habe mir die Komponente gleich mal angeschaut. Leider erfüllt sie nicht die Anforderungen, die ich für die gewünschte Funktionalität meines Programmes stelle. ( Und meine Bedürfnisse erfüllt die sowieso nicht
)
-
@Geschwindigkeitsmessung:
So, habe jetzt mal mit QueryPerformanceCounter gemessen:Kolumbus' Version: ~35ns/50ns (IsChecked / IsNotChecked)
Braunsteins Version: ~20ns/40nsIch komme da nicht auf Faktor 20. Leider verstehe ich die Messung mit QPC nicht ganz, daher kann ich nicht bewerten wie aussagekräftig die Ergebnisse sind.
Hier mal die beiden "Messaufbauten":
// Kolumbus' Version: void __fastcall TForm4::CheckBoxClick(TObject *Sender) { unsigned short j= static_cast<TCheckBox*>(Sender)->Tag; LARGE_INTEGER Frequenz, AnfangsWert, EndWert; unsigned __int64 Latenz; double ErgebnisWert; QueryPerformanceFrequency(&Frequenz); QueryPerformanceCounter(&AnfangsWert); QueryPerformanceCounter(&EndWert); Latenz= EndWert.QuadPart - AnfangsWert.QuadPart; QueryPerformanceCounter(&AnfangsWert); for(unsigned short k= 0; k < (ComponentCount-1); k++) { if((Components[k]->ClassNameIs("TEdit")) && (static_cast<TEdit*>(Components[k])->Tag==j)) { TEdit *VirtualEdit= static_cast<TEdit*>(Components[k]); if(!VirtualEdit->Enabled) VirtualEdit->Enabled= true; else { VirtualEdit->Enabled= false; VirtualEdit->Text= "0"; } break; } } QueryPerformanceCounter(&EndWert); ErgebnisWert= ((((double)AnfangsWert.QuadPart - (double)EndWert.QuadPart) - (double)Latenz) / (double)Frequenz.QuadPart); ErgebnisWert*= -1000000; Label3->Caption= FloatToStrF(ErgebnisWert, ffFixed, 16, 2) + " ns"; }//Braunsteins Version: void __fastcall TForm4::CheckBoxClick(TObject *Sender) { unsigned short j= static_cast<TCheckBox*>(Sender)->Tag; LARGE_INTEGER Frequenz, AnfangsWert, EndWert; unsigned __int64 Latenz; double ErgebnisWert; QueryPerformanceFrequency(&Frequenz); QueryPerformanceCounter(&AnfangsWert); QueryPerformanceCounter(&EndWert); Latenz= EndWert.QuadPart - AnfangsWert.QuadPart; QueryPerformanceCounter(&AnfangsWert); for(unsigned short k= 0; k < (ComponentCount-1); k++) { TEdit *VirtualEdit= dynamic_cast<TEdit*>(Components[k]); if((VirtualEdit) && (VirtualEdit->Tag==j)) { if(!VirtualEdit->Enabled) VirtualEdit->Enabled= true; else { VirtualEdit->Enabled= false; VirtualEdit->Text= "0"; } break; } } QueryPerformanceCounter(&EndWert); ErgebnisWert= ((((double)AnfangsWert.QuadPart - (double)EndWert.QuadPart) - (double)Latenz) / (double)Frequenz.QuadPart); ErgebnisWert*= -1000000; Label3->Caption= FloatToStrF(ErgebnisWert, ffFixed, 16, 2) + " ns"; }Woher hast Du den Faktor 20 Braunstein?
-
Kolumbus: Du hast ja auch nicht nur den Unterschied zwischen IsClass und dynamic_cast gemessen, sondern im wesentlichen deine Schleife (wo der Aufruf von IsClass bzw. dynamic_cast untergeht).
Du mußt einfach eine Schleife mit mehreren Millionen Operationen ausführen, in der nur IsClass bzw. dynamic_cast ausgeführt wird und dafür dann die Zeit messen.
-
Ich habe einfach folgende Schleifen ausgeführt, und die Ausführungszeit gemessen.
for( int i=0; i<500000; ++i) bool test = Sender->ClassNameIs("TEdit"); for( int i=0; i<500000; ++i) bool test = dynamic_cast<TEdit*>(Sender);Das natürlich innerhalb einer OnClick-Funktion.
-
Th schrieb:
Du hast ja auch nicht nur den Unterschied zwischen IsClass und dynamic_cast gemessen, sondern im wesentlichen deine Schleife (wo der Aufruf von IsClass bzw. dynamic_cast untergeht).
Dankeschön, das ist Alles was ich wissen wollte!
Wie realistisch ist das denn, wenn ich die Zeit für zig-tausend gleiche Funktionsaufrufe messe, ohne den restlichen Kontext zu betrachten? Ich halte das Ergebnis nicht für praxisrelevant. Aber ein schöner Laborwert!

-
Du kannst ja jetzt noch die Schleife über deine Komponenten hinzufügen (aber ohne weitere Aktionen auszuführen).
Oder aber du testest die beiden Varianten mit unterschiedlichen Eingaben (aber ich bin mir sicher, daß der String-Vergleich mittels IsClass immer langsamer sein wird, als dynamic_cast - egal für welche Komponente).
Wobei die Frage eigentlich für deine kleine Schleife eigentlich völlig egal ist.