const hinter Funktion
-
fred001 schrieb:
wx++ schrieb:
Ist das hässlich so?
Ja.
Begründung? Was willst du mit deinem Code aussagen? Der ist unnütz.
Es geht um eine Funktion, die nichts am Objekt ändert, aber keinen konstanten Pointer zurückgeben soll, da danach mit diesem gearbeitet wird.
Eine
const
-Funktion gerantiert nicht nur, dass die Funktion selbst am Objekt nichts ändert, sondern auch, dass aufgrund des Aufrufs an anderer Stelle keine Änderungen erfolgen dürfen.
Deshalb darf man aus einerconst
-Funktion auch nur andereconst
-Funktionen aufrufen. Beinon-const
-Funktionen gibt es einen Fehler.
Dein Kram unterläuft diesen Mechanismus und führt im Falle eines tatsächlich alsconst
deklarierten Objekts zu undefiniertem Verhalten.wx++ macht es richtig.
-
Man sollte vielleicht noch erwähnen, dass man durch einen falschen Rückgabewert einer konstanten Funktion die Member trotzdem kompromitiert werden können. Bestes Beispiel für die falsche Verwendung ist die Rückgabe eines Zeigers auf einen Member.
-
HighLigerBiMBam schrieb:
Man sollte vielleicht noch erwähnen, dass man durch einen falschen Rückgabewert einer konstanten Funktion die Member trotzdem kompromitiert werden können. Bestes Beispiel für die falsche Verwendung ist die Rückgabe eines Zeigers auf einen Member.
Das geht auch nur mit const_cast. Man muss es also schon ziemlich mutwillig so weit treiben.
-
Soll vorkommen ^^
Compiler wirft Fehler, Fehler wird "behoben" und BOOM ^^
-
Klar, man kann auch
#define private public
machen, um "Fehler" zu beheben.
-
Das ist nicht mutwillig, sondern fahrlässig
Wenn man sicher gehen möchte, dass kein Unfug mit der Rückgabe getrieben wird hilft die Rückgabe einer Kopie.Um noch bei deinem #define private public zu bleiben. #define const ist auch top!
-
private und const sind Schl+sselwörter. Die Verwendung von Schlüsselwörter als "Makro-Namen" ist meines Wissens nach U.B.
-
U.B. ? Mein Compiler schluckt den sche.... kommentarlos.
-
krümelkacker schrieb:
private und const sind Schl+sselwörter. Die Verwendung von Schlüsselwörter als "Makro-Namen" ist meines Wissens nach U.B.
Der Beitrag war nicht so wirklich ernst gemeint und bezog sich auf das Wegcasten von
const
.
-
> Der Beitrag war nicht so wirklich ernst gemeint
War schon klar.
> U.B. ? Mein Compiler schluckt den sche.... kommentarlos.
Ich sehe hier keinen Widerspruch.
-
Ein blödes const-Problem, das ich in letzter Zeit hatte, war folgendes: In einer Library gab es einige typedefs:
typedef __mpfr_struct mpfr_t[1]; typedef __mpfr_struct *mpfr_ptr;
Nun hatte ich in meiner Klasse folgendes
class Number { mpfr_t mpfr_number; public: //.... mpfr_ptr get_mpfr_number() //es muss ein Pointer zurückgegeben werden, da ein Array nicht zurückgegeben werden darf { return mpfr_number; } const mpfr_ptr get_mpfr_number() const //Compiler meckert: warning: type qualifiers ignored on function return type { return const_cast<const mpfr_ptr>(mpfr_number); //ohne gings nicht } }
Was war das Problem? const mpfr_ptr ist ein konstanter Pointer, der auf variablen Inhalt zeigt. Ich brauche aber einen variablen Pointer, der auf konstanten Inhalt zeigt. Das geht AFAIK nur mit const __mpfr_struct *, da __mpfr_struct * const, const mpfr_ptr sowie mpfr_ptr const alles konstante Pointer sind. Wer garantiert mir jetzt, dass der struct-Name nicht in der nächsten Version der Library geändert wird? In der Dokumentation wurden, soweit ersichtlich, nur die typedef-Namen gebraucht.
-
Du gibst einen konstanten Zeiger zurück. Du willst aber einen Zeiger auf ein konstantes Objekt zurückgaben:
typedef __mpfr_struct *mpfr_ptr; typedef __mpfr_struct const * const_mpfr_ptr; const_mpfr_ptr get_mpfr_number() const
-
Tachyon schrieb:
Du gibst einen konstanten Zeiger zurück. Du willst aber einen Zeiger auf ein konstantes Objekt zurückgaben:
typedef __mpfr_struct *mpfr_ptr; typedef __mpfr_struct const * const_mpfr_ptr; const_mpfr_ptr get_mpfr_number() const
Das habe ich doch schon gesagt. Ich war mir bloß unsicher, ob von der Library garantiert wird, dass sich der Name von __mpfr_struct nicht ändert.
-
wxSkip schrieb:
[...]Das habe ich doch schon gesagt. Ich war mir bloß unsicher, ob von der Library garantiert wird, dass sich der Name von __mpfr_struct nicht ändert.
Ich habe nicht zu ende gelesen, sorry. Selbst wenn sich der Name der Struktur ändern sollte: Der Änderungsaufwand würde sich ja nur auf den
typedef
beschränken. So schlimm sollte das also eigentlich nicht sein.
-
Tachyon schrieb:
wxSkip schrieb:
[...]Das habe ich doch schon gesagt. Ich war mir bloß unsicher, ob von der Library garantiert wird, dass sich der Name von __mpfr_struct nicht ändert.
Ich habe nicht zu ende gelesen, sorry. Selbst wenn sich der Name der Struktur ändern sollte: Der Änderungsaufwand würde sich ja nur auf den
typedef
beschränken. So schlimm sollte das also eigentlich nicht sein.Da hast du natürlich recht. Es kam mir auch mehr aufs Prinzip an (und die Syntax hat mich ein bisschen geärgert, weil ich erst eine Woche danach draufgekommen bin).
-
Man könnte natürlich auch mit type_traits den Zeigertypen bauen:
typedef remove_pointer<mpfr_ptr>::type const* const_mpfr_ptr;
oder ohne Abhängigkeit von C++0x/Boost/TR1:
template<class T> struct constify_pointee; template<class T> struct constify_pointee<T*> { typedef T const* type; }; template<class T> struct constify_pointee<T*const> { typedef T const*const type; }; ... typedef constify_pointee<mpfr_ptr>::type const_mpfr_ptr;
Wenn die Bibliothek (GNU MPFR?) so einen typedef nicht anbietet, dann wird "const" dort wahrscheinlich auch kaum benutzt. Dann würde dir ein solcher Zeiger natürlich nicht viel bringen ... es sei denn, du magst const_cast vor Funktionsaufrufen anwenden...
-
krümelkacker schrieb:
Wenn die Bibliothek (GNU MPFR?) so einen typedef nicht anbietet, dann wird "const" dort wahrscheinlich auch kaum benutzt. Dann würde dir ein solcher Zeiger natürlich nicht viel bringen ... es sei denn, du magst const_cast vor Funktionsaufrufen anwenden...
Ja, es ist MPFR. In der Doku steht zwar nie was von const-Argumenten, ich kann diese const-Pointer aber problemlos anwenden (keine Compilerwarnung bei höchster Warnungsstufe), auch in const-Funktionen.
Natürlich übergebe ich als Element, das verändert wird, auch keinen const-Pointer.
-
Hm... habe das gerade mal getestet und ein komisches Ergebnis bekommen...
#include <iostream> using namespace std; class test { //... }; typedef test my_t[1]; typedef test *my_ptr; typedef const test *const_my_ptr; typedef test *const my_const_ptr; class abc { my_t tmp; public: my_ptr gettmp(){cout << "normal function called\n"; return tmp;} const_my_ptr gettmp() const{cout << "const function called\n"; return tmp;} }; void func(const my_t in) { cout << "const my_t in\n"; } void func(my_t in) { cout << "my_t in\n"; } template<typename T>T const &get_obj(T const &in){return in;} template<typename T> T &get_obj(T &in){return in;} int main() { abc val1; const abc val2 = abc(); func(val1.gettmp()); //output: "normal function called\n my_t in\n" func(get_obj(val1).gettmp()); //output: "normal function called\n my_t in\n" func(val2.gettmp()); //output: "const function called\n const my_t in\n" func(get_obj(val2).gettmp()); //output: "const function called\n const my_t in\n" func(abc().gettmp()); //output: "normal function called\n my_t in\n" !!!??? func(get_obj(abc()).gettmp()); //output: "const function called\n const my_t in\n" }
Macht man die const-Version von func() weg, gibt's Konvertierungs-Errors.
-
wxSkip schrieb:
Hm... habe das gerade mal getestet und ein komisches Ergebnis bekommen...
[...]
Macht man die const-Version von func() weg, gibt's Konvertierungs-Errors.Das ist nicht verwunderlich. Du kannst einen Zeiger vom Typ "const T*" nicht ohne const_cast nach "T*" konvertieren. Und das ist auch genau das, was ich meinte. Wenn Du da jetzt ein const dranfriemelst, kannst Du mit einem solchen Zeiger nichts mehr anfangen, da all die Bibliotheksfunktionen einen non-const Zeiger haben wollen, obwohl sie nicht alle das Objekt verändern. Du spührst hier den "viralen Effekt" von const.
Lösung 1: Vergiss const
Lösung 2: Bau Dir eine Zwischen-Schicht zwischen Deinem Programm und MPFR. Im einfachsten Fall sind das Wrapper-Funktionen, die ggf const_cast intern benutzen und die Aufrufe weiter an MPFR leiten.Beipsiel:
int bloede_c_funktion_ohne_const(int*x) { printf("%d\n",*x); // *x wird nicht geändert return *x + 3; // *x wird nicht geändert } inline int const_korrekter_wrapper(const int*x) { return bloede_c_funktion_ohne_const(const_cast<int*>(x)); }
kk
-
Das mit den Konvertierungs-Errors war nur eine Anmerkung. Mit dem verwunderlichen meinte ich, dass abc().gettmp() nicht die const-Version von gettmp() aufruft, obwohl abc() ein rvalue ist. Ich habe ja keine Probleme mit MPFR, daher benutzt die Bibliothek anscheinend const mpfr_t-Parameter, auch wenn davon in der Doku nicht die Rede ist.