VC++ zeigt Warnung C4238 wenn ich bei Aufruf der Funktion
UpdateAllViews() die Adresse der Klassen-Variable CHintCenter, wie im
Code zu sehen, übergebe. Also ohne vorherige Definition einer Variablen
vom Typ CHintCenter. Das funktioniert so, aber kann ich das anders
schreiben, ohne eine zusätzliche Variable, damit die Warnung nicht
kommt? Ähnliche Konstrukte habe ich sehr viele und möchte den
Schreibaufwand einer Variablendefinition vermeiden.
Leider finde ich nur die Antwort, es gibt keine elegante Lösung. Meine
Hoffnung ist aber, in all dem Firlefanz den man in den aktuellen C++
Standard gepackt hat, findet sich etwas Passendes.
Die elegante Lösung steht im zweiten Beitrag, ist die Option /ZE, und
das Gottvertrauen, daß du weißt, was du tust.
Alternativ schreib ein #pragma warning (disable : 4238) davor.
Oliver
Mixer schrieb:> VC++ zeigt Warnung C4238 wenn ich bei Aufruf der Funktion> UpdateAllViews() die Adresse der Klassen-Variable CHintCenter,
Im C++-Sprachgebrauch gibt es keine Klassen-Variablen (wäre z.B.
Java-Speech). Meinst Du ein statisches Datenelement? Das wäre hier aber
auch nicht der Fall.
> wie im> Code zu sehen, übergebe. Also ohne vorherige Definition einer Variablen> vom Typ CHintCenter. Das funktioniert so, aber kann ich das anders> schreiben, ohne eine zusätzliche Variable, damit die Warnung nicht> kommt? Ähnliche Konstrukte habe ich sehr viele und möchte den> Schreibaufwand einer Variablendefinition vermeiden.
Suche mal nach temp. Objekte und Address-Operator ...
Mixer schrieb:> Ähnliche Konstrukte habe ich sehr viele und möchte den> Schreibaufwand einer Variablendefinition vermeiden.
dann ändere die Signatur von UpdateAllViews(), sodass sie eine Referenz
auf eine Konstante nimmt. (Kleiner Tipp, die Deklaration von CHintCenter
hat mit dem "Problem" überhaupt nichts zu tun und eine Kopie der Warnung
könnte auch nicht schaden):
> Meine Hoffnung ist aber, in all dem Firlefanz den man in den aktuellen C++
Standard gepackt hat, findet sich etwas Passendes.
Dann beschäftige Dich doch mal mit C++. Die Adresse eines temporaries zu
nehmen, war noch nie gültiges C++.
soll doch schrumpfen.
Dr. Sommer schrieb:> PS: Länge und Breite als float? Ob das genau genug ist...?
Lat/Lon sind als lokalisierender float Wert genau genug. Nur bei der
Berechnung mit Winkelfunktionen muss man zu double übergehen.
> soll doch schrumpfen.
Das Problem liegt in der Signatur von UpdateAllViews(...).
Wahrscheinlich ist die Verwendung eines rohen Zeigers auf ein lokales
Objekt eh falsch bzw. unsinnig. Daher die Frage: liegt die Funktion in
Deinem Einflussbereich, um sie zu ändern?
Mixer schrieb:> Ein Sakrileg, an der Weisheit der Compiler-Bauer zu zweifeln.
Nur weil ein Programm ohne Warnungen kompiliert, ist es noch lange nicht
korrekt. Es ist unmöglich einen Compiler zu bauen, der alle Probleme
findet ( Satz von Rice).
Solche Warnungen des Compilers sind auch wirklich lästig. Auch die
Ratschläge, dass Problem verstehen zu lernen, sidn ja voll nervig.
Deswegen folgender Tipp für Dein Problem und ähnliche Probleme in der
Zukunft: vor dem fraglichen Codeabschnitt:
Wilhelm M. schrieb:> Deswegen folgender Tipp für Dein Problem und ähnliche Probleme in der> Zukunft: vor dem fraglichen Codeabschnitt:
die Abfrage, ob es sich um den MSVC handelt, kannst Du Dir sparen, der
Code ist so eh nicht portabel.
Mixer schrieb:> Ähnliche Konstrukte habe ich sehr viele und möchte den> Schreibaufwand einer Variablendefinition vermeiden.> class CHintCenter : public CObject> {> public:> CHintCenter(float fLat = 0.0f, float fLon = 0.0f)> : m_fLat(fLat), m_fLon(fLon) { }>> float m_fLat, m_fLon;> };>> pDoc->UpdateAllViews(NULL, HINT_UPDATE_CENTER, &CHintCenter(fLat, fLon));
Also wenn schon eine eigen Klasse notwendig ist, die nur zu diesem Zweck
existiert, dann schlage ich einen Cast-Operator vor:
Mixer schrieb:> operator CHintCenter*() { return this; }tictactoe schrieb:> operator ObjPtr() { return this; }
Mal davon abgesehen das eure Lösung falsch ist, glaubt ihr wirklich,
dass es eine user-defined conversion function in diesem Fall eine gute
Idee ist?
In einem Fall wird eine Adresse eines temporären Objektes auf dem Stach
übergeben, im anderen das Objekt selbst (per value).
Im letzteren Fall hat der Compiler die gesamte Lebensdauer des Objekts
unter Kontrolle. Sobald man innerhalb der gerufenen Funktion beginnt die
Adresse des Parameters weiterzureichen, sollte eigentlich dann wieder
die Warbubg kommen.
Torsten R. schrieb:> Wilhelm M. schrieb:>>> Deswegen folgender Tipp für Dein Problem und ähnliche Probleme in der>> Zukunft: vor dem fraglichen Codeabschnitt:>> die Abfrage, ob es sich um den MSVC handelt, kannst Du Dir sparen, der> Code ist so eh nicht portabel.
Ok, mag sein ... das kann ich an dem Codeschnipsel nicht beurteilen bzw.
sehe dort keinen Grund für fehlende Portabilität.
Andere Compiler als der MSVC++ würden dann wiederum Warnungen wegen
"unknown pragma" ausgeben.
Wilhelm M. schrieb:> Ok, mag sein ... das kann ich an dem Codeschnipsel nicht beurteilen bzw.> sehe dort keinen Grund für fehlende Portabilität.
Weil es in der Sprache C++ nicht erlaubt ist, die Adresse eines
temporären Objektes zu nehmen. Alle anderen Compiler werden das als
Fehler ablehnen.
mh schrieb:> Mixer schrieb:>> operator CHintCenter*() { return this; }>> tictactoe schrieb:>> operator ObjPtr() { return this; }>> Mal davon abgesehen das eure Lösung falsch ist, glaubt ihr wirklich,> dass es eine user-defined conversion function in diesem Fall eine gute> Idee ist?
Also, man muss das Ganze schon ein bisschen pragmatischer und im Kontext
sehen. Pauschalaussagen wie "Pointer auf temporäre Objekte sind um jeden
Preis zu vermeiden" bringen einen bald an die Grenzen.
In diesem Fall handelt es sich um die Funktion
CDocument::UpdateAllViews(), und man muss schon wissen, was die macht.
Konkret legt sie nur eine sehr, sehr vage Bedeutung für den 2. und 3.
Parameter fest. Es bleibt also in der Verantwortung des Verwenders, wie
mit denen umgegangen wird.
Und wenn Mixer nicht völlig daneben ist, dann passiert mit dem
durchgereichten Pointer nichts anderes als dass er wieder in
CHintCenter* gecastet wird, die beiden Members ausgelesen werden, und
dann der Pointer nie wieder angeschaut wird.
tictactoe schrieb:> Also, man muss das Ganze schon ein bisschen pragmatischer und im Kontext> sehen. Pauschalaussagen wie "Pointer auf temporäre Objekte sind um jeden> Preis zu vermeiden" bringen einen bald an die Grenzen.
Es gäbe aber eine ganz pragmatische und "korrekte" Lösung: Einfach die
Paramter per const ref nehmen. Wenn man die Funktion selbst nicht ändern
kann, dann wäre es ein ganz pragmatischer Einzeiler, da eine Funktion zu
schreiben:
Torsten R. schrieb:> Gültiges C++, keine Warning, keine gefährliche Konvertierungen.
Der Pointer ist dann const. UpdateAllViews möchte aber einen nicht const
Pointer. Ich hab doch oben 3 korrekte Lösungen genannt, was ist schlecht
an denen?
Dr. Sommer schrieb:> Torsten R. schrieb:>> Gültiges C++, keine Warning, keine gefährliche Konvertierungen.>> Der Pointer ist dann const. UpdateAllViews möchte aber einen nicht const> Pointer.
Ja, stimmt. Dann eben eine Kopie.
> Ich hab doch oben 3 korrekte Lösungen genannt, was ist schlecht> an denen?
Überhaupt nichts (ich würde kein Template nehmen, da die anschließende
Konvertierung nach void* das Typsystem umgeht; ich würde eher einen Satz
überladener Funktionen nehemen)!
Frage bitte nicht mich, warum hier einige sich gegen korrekte Lösungen
wehren und sich unbedingt mit inpliziten Konvertierungen in den Fuß
schießen wollen. Ich wollte auf das Stichwort "Pragmatisch" hin, nur
noch mal aufzeigen, dass das konkrete Problem wirklich einfach, robust
und korrekt zu lösen ist.
Torsten R. schrieb:> da die anschließende Konvertierung nach void* das Typsystem umgeht;
Wo wird denn nach void* konvertiert? Laut Internet will UpdateAllViews
ein CObject *. Das template hilft wenn man verschiedene Varianten mit
verschiedenen Parameter Typen hat.
Dr. Sommer schrieb:> Torsten R. schrieb:>> da die anschließende Konvertierung nach void* das Typsystem umgeht;>> Wo wird denn nach void* konvertiert? Laut Internet will UpdateAllViews> ein CObject *. Das template hilft wenn man verschiedene Varianten mit> verschiedenen Parameter Typen hat.
Torsten R. schrieb:> Den Fehler würde der Compiler finden können, wenn updateAllViews() kein> Template wäre.
Der Compiler würde hier machen dass ein CHintCenter ** nach CObject *
konvertiert wird
Dr. Sommer schrieb:> Torsten R. schrieb:>> Der Compiler würde hier machen dass ein CHintCenter ** nach CObject *> konvertiert wird
Genau und dem OP folgend, wäre das wohl nicht gewünscht und ein Fehler.
Und wir machen doch alle C++, weil wir wollen, dass der Compiler unsere
Fehler möglichst früh findet.
Torsten R. schrieb:> Und wir machen doch alle C++, weil wir wollen, dass der Compiler unsere> Fehler möglichst früh findet.
Naja ob der Compiler den Fehler jetzt beim äußeren oder beim inneren
Funktionsaufruf anzeigt...
Dr. Sommer schrieb:> Naja ob der Compiler den Fehler jetzt beim äußeren oder beim inneren> Funktionsaufruf anzeigt...
In dem Fehlerfall, den ich skiziert habe, generiert der Compiler keinen
Fehler.
Torsten R. schrieb:> In dem Fehlerfall, den ich skiziert habe, generiert der Compiler keinen> Fehler.
Doch:
Dr. Sommer schrieb:> Der Compiler würde hier machen dass ein CHintCenter ** nach CObject *> konvertiert wird
Es sollte natürlich meckern und nicht machen heißen. Danke
Autokorrektur
Dr. Sommer schrieb:> Torsten R. schrieb:>> In dem Fehlerfall, den ich skiziert habe, generiert der Compiler keinen>> Fehler.>> Doch:
Ah, ich war davon ausgegangen, dass der letzte Parameter ein void* ist
(nicht ein CObject*). Zum Glück muste ich mit MFC nie arbeiten.
Torsten R. schrieb:> Wilhelm M. schrieb:>> Ok, mag sein ... das kann ich an dem Codeschnipsel nicht beurteilen bzw.>> sehe dort keinen Grund für fehlende Portabilität.>> Weil es in der Sprache C++ nicht erlaubt ist, die Adresse eines> temporären Objektes zu nehmen. Alle anderen Compiler werden das als> Fehler ablehnen.
Es sei denn, der potentielle, mutige GCC Nutzer benutzt so wie der TO
den Schalter /Ze auch die Option -fpermissive ...
Vermutlich war const noch nicht erfunden, als die Grundlagen für die MFC
zusammenengebastelt wurden...
Immerhin findet Google für das „Problem“ mit der Warnung Beiträge von
1995...
Oliver
Oliver S. schrieb:> Vermutlich war const noch nicht erfunden, als die Grundlagen für die MFC> zusammenengebastelt wurden...>> Immerhin findet Google für das „Problem“ mit der Warnung Beiträge von> 1995...>> Oliver
Wohl kaum: const existiert in C++ seit "C with Classes" (lt. Wikipedia
seit 1981) und MFC ist lt. Wikipedia von 1992.
Natürlich. Aber sowas wie const correctness war in „C mit Classes“ lange
Zeit nicht so wirklich ein Thema, was man ja auch an MFC deutlich sieht.
Unter MFC steckt ein in Windows-Unterbau, dessen Ursprünge bis zu MS-DOS
zurückreichen, und den Bill Gates noch persönlich in seiner Garage
programmiert hat (oder es als zumindest als seins verkauft hat)
Oliver
Wilhelm M. schrieb:> Oliver S. schrieb:>> Vermutlich war const noch nicht erfunden, als die Grundlagen für die MFC>> zusammenengebastelt wurden...>>>> Immerhin findet Google für das „Problem“ mit der Warnung Beiträge von>> 1995...>>>> Oliver>> Wohl kaum: const existiert in C++ seit "C with Classes" (lt. Wikipedia> seit 1981) und MFC ist lt. Wikipedia von 1992.
Allerdings wurde C++ erst 1998 genormt. Davor gab es nicht wirklich DAS
Standard-Regelwerk, an das sich alle (oder zumindest viele) zu halten
versuchen. Also hat man sich bei Microsoft vermutlich um
const-Korrektheit noch nicht geschert - vermutlich auch aus dem
gewohnten laxen Umgang damit in C heraus.