Änderungen von Variablen in Variable speichern
-
Werner Salomon schrieb:
Has3 schrieb:
Da ich mich ja weiterbilden will
wollt ich wissen ob es da noch etwas eleganteres gibt.Ja, man kann da ein kleines Template bauen, welches jede Änderung registriert - etwa sowas...
wie schon erwähnt: edit-controls kann man fragen, ob sich was verändert hat.
so elegant ein template sein mag (templates zu nutzen ist ja irgendwie immer elegant
), aber funktionalität nachzubauen, die schon existiert, ist niemals elegant.Simon2 schrieb:
Konrad Rudolph schrieb:
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
Weil ich meine Abneigung (die ich immer noch verspüre) in diesem Fall nicht konkret begründen kann.
kann es denn der Konrad begründen?

-
vista schrieb:
Simon2 schrieb:
Konrad Rudolph schrieb:
Simon2 schrieb:
trotzdem ziehe ich meinen Einwand zurück: "Unschön" ist das nicht.
Wieso so zimperlich? '#define' für Konstanten ist grundsätzlich unschön.
Weil ich meine Abneigung (die ich immer noch verspüre) in diesem Fall nicht konkret begründen kann.
kann es denn der Konrad begründen?

Ich denke, das kann er. Es gibt in C++ (im Gegensatz zu C) ein Sprachelement, welches das Definieren von Konstanten erlaubt. Damit gibt es keinen Grund mehr, auf den Präprozessor auszuweichen, welcher mehrere Nachteile hat:
- (a priori) keine Typensicherheit,
- zerstört die Logik des Programms und erschwert das Debuggen,
- stellt prinzipiell keinen konstanten Wert dar (s. Beispiel 1),
- ist fehleranfällig (z.B. durch vergessene Klammern, Beispiel 2),
- last, but not least: Zerstört Namensbereich-Zuordnungen und ist somit destruktiv.// So macht man es in C++: namespace math { const double pi = std::atan(1.0) * 4.0; } // So macht man es nicht. // Beispiel 1, wird jedes Mail neu berechnet, wenn der Code benutzt wird: #define pi (std::atan(1.0) * 4.0) cout << pi << endl; // Wert wird berechnet cout << pi << endl; // Wert wird erneut berechnet. // Beispiel 2, hier ham' wir den Salat. #define drei 2 + 1 cout << drei * 4 << endl;
-
Konrad Rudolph schrieb:
#define pi (std::atan(1.0) * 4.0) #define drei 2 + 1du hast es absichtlich falsch gemacht. damit kannst du niemanden überzeugen.
#define pi 3.1415926536 #define drei (2 + 1)nun sind die fehler weg.

-
gut zu wissen

werd mir mal das template anschaun wenn ich zeit hab.vielen Dank für die Hilfe
-
// irgendwo in den Weiten der Headers der vielen Libraries... // x1.h void drei(); enum { pi };// eigene header // A1.h #define pi 3.1415926536 #define drei (2 + 1)#include <eine_header_die_irgend_eine_header_X1_includiert.h> #include "A1.h" void foo() { int i = drei * pi; }Viel Spass bei der Fehlersuche!!!!!

-
vista schrieb:
du hast es absichtlich falsch gemacht. damit kannst du niemanden überzeugen.
Bei der Verwendung von PI ist mir eine exakt berechnete Version auf jeden Fall lieber als ein fest vorgegebener Wert (klar, für die meisten Anwendungen reicht sogar 3.14, aber sag das mal einem Puristen :D). Und ansonsten zeigen die Beispiele recht deutlich die Probleme des Präprozessors - #define ist eine dumpfe Textersetzung und wenn dabei Fehler auftreten, kannst du die nur schwer lokalisieren.
In C war #define womöglich noch verwendbar, aber in C++ ist es in den meisten Fällen unnötig (da gibt es Möglichkeiten mit vergleichbarer Anwendbarkeit, aber ohne die Schwächen des Präprozessors).
-
vista schrieb:
Konrad Rudolph schrieb:
#define pi (std::atan(1.0) * 4.0) #define drei 2 + 1du hast es absichtlich falsch gemacht.
Natürlich. Ich sagte ja auch, es sei fehleranfällig. Was glaubst Du, wie häufig diese Klammern vergessen werden!
damit kannst du niemanden überzeugen.
Jedem das seine. Aber in großen Teamprojekten ist man über jede eliminierte potentielle Fehlerquelle froh.
Natürlich kann man auch mit #defines's fehlerfreien Code schreiben, das habe ich nicht bestritten. Aber es ist definitiv schwerer, als wenn man es sein lässt.
#define pi 3.1415926536Ich bevorzuge die Definition über den Arkustangens.
-
ok, dass #define grundsätzlich fehlerträchtiger ist als etwas anderes kann ich nicht nachvollziehen, denn meistens handelt man sich fehlerquellen durch falsche anwendung ein und das kann auch mit anderen konstrukten passieren.
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
aber da ich von C++ null plan habe (ich programmiere meistens C), schenke ich euch mein blindes vertrauen und glaube euch, dass es in C++ andere möglichkeiten gibt, die besser ins konzept der sprache passen und die man als C++ progger deshalb #define vorziehen sollte.

-
vista schrieb:
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
Echt? Das beste, was der Präprozessor "rechnen" kann, sind die Operatoren # und ##. Bei einem
#define drei (1+2)wird jedes Vorkommen von 'drei' textuell ersetzt, ohne daß der Präprozessor sind den Inhalt der Ersetzung ansieht - der Rest ist dann Sache des Compilers (der die Berechnung von (1+2) rausoptimieren kann).
-
CStoll schrieb:
vista schrieb:
..und dass #define immer eine stumpfe textersetzung macht ist auch nicht ganz richtig. etwas rechnen kann es ja auch.
Echt? Das beste, was der Präprozessor "rechnen" kann, sind die Operatoren # und ##. Bei einem
#define drei (1+2)wird jedes Vorkommen von 'drei' textuell ersetzt, ohne daß der Präprozessor sind den Inhalt der Ersetzung ansieht - der Rest ist dann Sache des Compilers (der die Berechnung von (1+2) rausoptimieren kann).ich kann mich jetzt täuschen, aber als ich mir mal c-code nach dem preprocessor-durchlauf angeschaut habe (war' s jetzt beim codewarrior?)
da wurde so etwas:#define drei (1+2) ... int x = drei;das:
int x = 3;mag aber sein, das in der regel die präprozessoren nicht so schlau sind...

-
Der Compiler macht eine 3 draus, wenn er das sieht. Aber nicht der Präprozessor. Und ja, du hast von C++ keinen Plan, sonst würdest du das nicht so in deinem jugendlichen Leichtsinn sagen, das Makros nicht so übel sind. Denn du mußt dir einem bewusst werden:
static const int hallo = 2;Das Ding verbraucht KEINEN Speicher. (außer der Compiler ist so dämlich, aber dann würde ich den nicht weiter benutzen) Ich habe also nicht nur wie Makros keinen Speicherverbrauch, sondern auch noch ein Sprach-Element in Gebraucht. Ich kann das Hallo sogar in einen Namespace legen. Das geht alles nicht mit Makros. Es gibt KEINEN Grund dafür, wenn man C++ programmiert.
-
Artchi schrieb:
static const int hallo = 2;Das Ding verbraucht KEINEN Speicher.
demnach müsste ein 'sizeof(hallo)' 0 ergeben.
ist es so?
wäre jedenfalls unlogisch wenn nicht...

-
Stimmt. *mir selbst in den arsch tritt*
-
Sizeof von hallo ergibt natürlich die Größe von int, und nicht 0. Wenn man die Adresse von hallo im Programm nimmt muss man auch (bei statischen Membern) Speicher für die Konstante zur Verfügung stellen, und dessen Größe ist logischerweise auch 4. Man könnte sogar mit const_cast-Gemeinheiten den Wert an dieser Stelle ändern.
Aber darum gehts garnicht, das wichtige ist doch dass solche Konstanten in C++ (im Gegensatz zu C) vom Compiler als konstant angesehen und damit zur Compile-Zeit ersetzt werden können. Selbst wenn Du den Wert per const_cast zur Laufzeit änderst ist der Compiler berechtigt davon auszugehen dass Du das nicht tust.
-
Es ist halt ein Sprach-Element und kein Textersetzer-Element. Man man sollte immer Sprachelemente bevorzugen. Da der Compiler die Hoheit über den endgültigen Code hat.
-
LordJaxom schrieb:
Sizeof von hallo ergibt natürlich die Größe von int, und nicht 0. Wenn man die Adresse von hallo im Programm nimmt muss man auch (bei statischen Membern) Speicher für die Konstante zur Verfügung stellen, und dessen Größe ist logischerweise auch 4. Man könnte sogar mit const_cast-Gemeinheiten den Wert an dieser Stelle ändern.
hmmm?

jetzt bin ich ganz schön verwirrt. konstanten, deren wert man zur laufzeit ändern kann? wie passt denn das zusammen
so langsam komme ich zu dem schluss, dass #define hierfür doch besser geeignet ist.
-
Lies Lordjaxoms Beitrag noch mal genauer durch. Er hat nicht gesagt, das man einfach so zur Laufzeit einen const-Wert ändern kann. Sondern du mußt das schon mit speziellen Mitteln (const_cast) explizit zun. Im Übrigen: in C++ benutzt man eh enums oder man kapselt const-Variablen als private in Klassen. DIE kann man definitiv nicht ändern. Auch nicht mit nem const_cast. Wir reden hier die ganze Zeit über normale Variablen. Aber C++ hat mehr Sprachmittel, mit denen ich sowas ausschliessen kann.
-
Um es nochmal zu spezifizieren: Man kann mit const_cast viel gemeines tun, sogar statische Memberkonstanten ändern. Können im Sinne von es compiliert.
Der Standard sagt aber dass das Entfernen von const und das darauffolgende Ändern eines Wertes nur dann definiert ist, wenn der Ursprungswert nicht konstant ist. Was undefiniert bedeutet, brauch ich Dir wohl nicht zu sagen

Das folgende Beispiel compiliert z.B. wunderbar, stürzt aber (MSVC++ 8.0, WinXP) mit einem Speicherzugriffsfehler ab, da der Ursprungswert konstant war.
class ConstGehampel { public: static const int guenelpf = 101; }; int main(int argc, char* argv[]) { cout << sizeof(ConstGehampel::guenelpf) << endl; // Hat Größe cout << &ConstGehampel::guenelpf << endl; // Hat Adresse cout << ConstGehampel::guenelpf << endl; const_cast<int&>(ConstGehampel::guenelpf) = 12; // BOOOOM cout << ConstGehampel::guenelpf << endl; }
-
vista schrieb:
ok, dass #define grundsätzlich fehlerträchtiger ist als etwas anderes kann ich nicht nachvollziehen, denn meistens handelt man sich fehlerquellen durch falsche anwendung ein und das kann auch mit anderen konstrukten passieren....
Ja - aber mit kaum einer Technik ist es so leicht, Fehler zu machen, wie mit #define-s !
Auf jeden Fall ist es viiiiiel schwerer, mit den obigen const-Konstrukten Fehler zu machen (fast nur mutwillig).Insgesamt teile ich genau die hier von Artchie, Konrad und CStoll formulierte Sorge bzgl. der Verwendung von #define-s.
Mein "unschön" habe ich nur zurückgezogen, weil ich diese Probleme im vorliegenden Fall ("FELD0 (1<<0)") nicht akut sehe.Gruß,
Simon2.
-
Wo ich auch C++ Sprachmittel den defines vorziehe:
#define EINS 1 #define ZWEI 2 #define DREI 3Uuuuumständlich. Wenn ich sowas in C++ habe:
enum {eins = 1, zwei, drei, zehn = 10, elf, zwoelf };Mit defines umständlicher, weil wenn ich mal eines "zwischenschieben" will, oder nur die Werte anders haben will, muß ich bei Makros schlechtestenfalls alle Makro-Werte ändern. enum zählt autom. weiter. Und ist noch typisiert.