Hallo,
erst mal zur Ausgangslage: Ein Programm, das GUI besitzt, startet einen
Thread, der nebenbei (ohne GUI zu blockineren) die Anzeige z.B. x-mal
pro y-Zeitheiten aktualisiert.
Den Verlauf steuert die (private) Klassenvariable "bool running". Man
sagt ja dass auf die Klassenvariablen per "set"/"get"-Methoden
zugegriffen werden soll.
Also bekommt die Klasse noch zwei public-Methoden:
1
voidset_running(boolnew_val);
2
boolget_running();
und dann wird die Anzeige erzeugt:
1
voidshow_something_on_the_screen(){
2
3
while(get_running()){
4
5
show_new_text();
6
delay(time);
7
8
}
9
}
Meine Frage: Ist es sinnvoll den Wert von running in der while-Schleife
ständig per Methode get_running() auszulesen? Oder ist es doch besser
direkt auf die Variable zuzugreifen? Also while(running) bla bla bla.
Danke!
Die getter/setter sind zum einen dazu da falsche Zuweisungen
auszuschließen.
Klassisches Besipiel: bei einer Klasse für eine Bruchzahl
wird 0 für den Nenner zugewiesen.
Wenn du direkten Zugriff auf die Variable hast, kannst du
die 0 zuweisen und das Programm schmiert eventuell ab.
Über eine set-Methode kannst du vorher prüfen, ob die
übergebene Zahl !=0 ist.
Bei einem Bool dürfte das egal sein, musst nur drauf achten,
dass du eine initiale Zuweisung im (Standard-)Konstruktor
hast, weil dein Bool sonst mit NULL initialisiert wird,
was weder true noch false ist.
Zum anderen kannst du aber im setter auch eine Änderungsmethode
abhandeln und damit deinem anderen Programmteil mitteilen,
dass sich deine Variable geändert hat, ohne pausenlos
den Zustand prüfen zu lassen.
Damit könntest du dir die while-Schleife eventuell sparen.
Alexander F. schrieb:> musst nur drauf achten,> dass du eine initiale Zuweisung im (Standard-)Konstruktor> hast, weil dein Bool sonst mit NULL initialisiert wird,
In der Annahme das der Codeschnippsel C++ ist:
1. Ein Bool kann per Definition nur die Werte true und false annehmen
kann. Er wird aber ganz sicher nicht mit NULL initialisiert.
2. Wenn eine Variable nicht initialisiert wird, hat sie einen
Zufallswert, naemlich den Wert der da gerade im Speicher steht, und
dieser Wert wird dann entweder als true oder als false interpretiert.
Sie wird nicht nur nicht mit NULL initialisiert, sie wird gar nicht
initialisiert.
3. In anderen Sprachen, wie z.B. Python gibt es neben True und False
noch das Nichts, None. Und None ist nochmal was anderes als NULL.
Alexander F. schrieb:> weil dein Bool sonst mit NULL initialisiert wird,> was weder true noch false ist.
In C++ gibt es nicht anderes als true und false fuer bool. Werte koennen
aber als true oder false interpretiert werden. Dabei gilt: Ein Wert = 0
wird als false, alle Werte != 0 als true interpretiert. NULL kann es an
der Stelle also nicht geben. Wenn du einem bool den Wert NULL zuweist,
wird dieser Wert vermutlich als false interpretiert werden.
Alexander F. schrieb:> Zum anderen kannst du aber im setter auch eine Änderungsmethode> abhandeln und damit deinem anderen Programmteil mitteilen,> dass sich deine Variable geändert hat
Ja, das hört sich besser an als ständig eine Prüffunktion aufzurufen.
Also prüfen in der "set"-Methode den Wert.
Und bei
running==false
gleich den Thread pausieren.
Und bei
running==true
den Thread fortsetzen.
Da hast du recht Kaj, war da wohl auf dem falschen Dampfer.
Bin momentan viel mit C# unterwegs, da wird sonst ales zu
null initialisiert, außer ein paar Primitive Datentypen wie
bool, int, float etc. dachte das gilt dort für alle Datentypen.
zitter_ned_aso schrieb:> Man> sagt ja dass auf die Klassenvariablen per "set"/"get"-Methoden> zugegriffen werden soll.
Man soll überhaupt nicht von außen in den Membervariablen herum
pfuschen.
Man kann aber einem Objekt irgendwas befehlen ( void start(); void
stop(); ) oder einen Status abfragen ( bool is_running(); ). Ob dahinter
irgendwelche Membervariablen abgefragt oder gesetzt werden, ist ein
Implementierungsdetail, das außerhalb der Klasse keinen etwas angeht.
Für jeden Member hingeklatschte Getter und Setter sind normalerweise
überflüssig. Wenn sie nicht überflüssig sind und von außen reger
Gebrauch davon gemacht wird, ist das ein Zeichen für unsauberes Design.
Kaj schrieb:> Alexander F. schrieb:>> weil dein Bool sonst mit NULL initialisiert wird,>> was weder true noch false ist.> In C++ gibt es nicht anderes als true und false fuer bool. Werte koennen> aber als true oder false interpretiert werden. Dabei gilt: Ein Wert = 0> wird als false, alle Werte != 0 als true interpretiert.
Das stimmt nicht ganz. Wenn du einen Integer nach bool konvertierst,
dann ist das von dir genannte die Regel, wie diese Konvertierung
stattfindet.
Darum geht's hier aber nicht, sondern um einen uninitialisierten bool,
in dem irgendwas drin stehen kann. Und je nachdem, wie bool auf dem
jeweiligen Compiler implementiert ist, kann sich da auch ein eigentlich
ungültiger Wert ergeben, der weder true noch false ist.
NULL ist natürlich Quatsch, denn das existiert nur im Zeigerkontext.
Rolf M. schrieb:> Und je nachdem, wie bool auf dem> jeweiligen Compiler implementiert ist, kann sich da auch ein eigentlich> ungültiger Wert ergeben, der weder true noch false ist.
Das ist richtig. Aber der Wert wird als true oder false interpretiert.
Das heisst aber nicht, das der Konkrete Wert true oder false ist. Und
genau dieser Wortlaut macht den Unterschied.
Kaj schrieb:> Werte koennen> aber als true oder false interpretiert werden. Dabei gilt: Ein Wert = 0> wird als false, alle Werte != 0 als true interpretiert.
Es gibt nur 2 Moeglihckeiten: Der Wert ist 0 oder eben nicht. Und dann
kann man den Wert auch interpretieren. Natuerlich kann ich einen bool
mit NULL initialisieren, macht nur halt nicht soviel Sinn.
Waere mir zumindestens nicht bekannt, das wenn du den Wert eines
uninitialisierten bools abfragt dann weder true noch false rauskommt.
1
#include<iostream>
2
3
usingnamespacestd;
4
5
6
intmain(void)
7
{
8
boolx;
9
10
if(x){
11
cout<<"true"<<endl;
12
}elseif(!x){
13
cout<<"false"<<endl;
14
}else{
15
cout<<"what ever"<<endl;
16
}
17
18
return0;
19
}
Spielt aber keine Rolle, da das undefined Behavior ist. Also ja, es
koennte alles raus kommen. Auch der Mann im Mond. :)
Kaj schrieb:> Rolf M. schrieb:>> Und je nachdem, wie bool auf dem>> jeweiligen Compiler implementiert ist, kann sich da auch ein eigentlich>> ungültiger Wert ergeben, der weder true noch false ist.> Das ist richtig. Aber der Wert wird als true oder false interpretiert.> Das heisst aber nicht, das der Konkrete Wert true oder false ist. Und> genau dieser Wortlaut macht den Unterschied.
Aber es bleibt komplett dem Compiler überlassen, welche Bitpatterns für
true und welche für false verwendet werden - oder was passiert, wenn man
einen bool hat, in dem keines dieser Bitpatterns steht, weil er nicht
auf dem offiziellen Weg mit einem Wert belegt wurde. Kann auch sein,
dass er an einer Stelle als true, an einer anderen als false
interpretiert wird.
> Es gibt nur 2 Moeglihckeiten: Der Wert ist 0 oder eben nicht.
Da er mehr als 1 Bit hat, gibt's mehr als 2 Möglichkeiten. Der Compiler
kann auch definieren, dass das Bitpattern 00000000 als false gilt und
11111111 als true und alles andere nicht weiter bedacht wird, da es in
einem gültigen Programm nicht vorkommt.
> Spielt aber keine Rolle, da das undefined Behavior ist. Also ja, es> koennte alles raus kommen. Auch der Mann im Mond. :)
Ja genau. Darauf wollte ich hinaus.
Du greifst also von mehreren Threads auf die Boolean-Variable zu? Dann
solltest du std::atomic_flag oder std::atomic<bool> benutzen, weil bei
einem "bool" von C++ nicht garantiert ist, dass gleichzeitige Zugriffe
konsistent sind. Ob es wirklich schief gehen kann hängt von der
Plattform ab, aber man möchte ja korrekten portablen Code schreiben...
Von mehreren Threads auf eine GUI zuzugreifen geht meistens sowieso
ziemlich schief.
Rolf M. schrieb:> Der Compiler kann auch definieren, dass das Bitpattern 00000000 als> false gilt und 11111111 als true und alles andere nicht weiter bedacht> wird, da es in einem gültigen Programm nicht vorkommt.
Welche Sprache? C? Dort ist der wert 0 als false und 1 als true
festgelegt. Und alle anderen Werte werden als true interpretiert.
Probleme gibt es also, wenn man irgendwie mit true vergleicht (No Go!)
Oder verschiedene bool-typen unterschiedlicher Bitbreiten hat und
zuweist (eigentlich auch ein No-Go)
A. S. schrieb:> Rolf M. schrieb:>> Der Compiler kann auch definieren, dass das Bitpattern 00000000 als>> false gilt und 11111111 als true und alles andere nicht weiter bedacht>> wird, da es in einem gültigen Programm nicht vorkommt.>> Welche Sprache? C?
Wir sprechen von C++, aber für C gilt das auch.
> Dort ist der wert 0 als false und 1 als true festgelegt. Und alle anderen> Werte werden als true interpretiert.
Da muss ich mich wiederholen:
Rolf M. schrieb:> Das stimmt nicht ganz. Wenn du einen Integer nach bool konvertierst,> dann ist das von dir genannte die Regel, wie diese Konvertierung> stattfindet.> Darum geht's hier aber nicht, sondern um einen uninitialisierten bool,> in dem irgendwas drin stehen kann.> Probleme gibt es also, wenn man irgendwie mit true vergleicht (No Go!)
Sofern du nicht bool, sondern z.B. int verwendest.
> Oder verschiedene bool-typen unterschiedlicher Bitbreiten hat und> zuweist (eigentlich auch ein No-Go)
Auch das gilt natürlich nur für irgendwelche selbst definierten Sachen,
die eigentlich Integer sind.
Auf Membervariablen nur durch Methoden zuzugreifen hat desweiteren auch
den Vorteil, dass man im Fehlerfall sich mit dem Debugger nur an einer
Stelle Gewehr-bei-Fuss aufstellen muss.
Der Unterschied beim Zugriff auf eine Variable als Zugriff auf die
Variable selbst und als Funktion liegt darin, dass die Funktion weitere
Aktionen enthalten kann. Im Lese- sowie im Schreibzugriff.
Die Variable kann zB auch in einem Ringbuffer liegen.