const hinter Funktion



  • Ist das hässlich so?

    Ja.

    #include <iostream>
    
    class Foo
    {
    public:
    
       Foo()
       {}
    
       const Foo* bar() const
       {
          std::cout << "Foo::bar() const" << std::endl;
          return this;
       }
    
       Foo* bar()
       {
          std::cout << "Foo::bar()" << std::endl;
          return this;
       }
    };
    
    int main()
    {
       Foo foo;
       Foo* f = foo.bar();
    
       const Foo cfoo;
       const Foo* cf = cfoo.bar();
    }
    


  • 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.



  • 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 einer const -Funktion auch nur andere const -Funktionen aufrufen. Bei non-const -Funktionen gibt es einen Fehler.
    Dein Kram unterläuft diesen Mechanismus und führt im Falle eines tatsächlich als const 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.


Anmelden zum Antworten