Wann nehme ich Objekt, Zeiger oder Referez?



  • gasi schrieb:

    Werner Salomon schrieb:

    CMyClass a;
        langFunc( boost::bind( &CMyClass::Meth1, &a, usw. ), .. weitere Parameter );
    

    warum soll man hier boost::bind verwenden?

    Muss man nicht. Das ist nur ein Beispiel. Der Funktor ist eine Möglichkeit die Schnittstelle zwischen der Klasse CMyClass und der Funktion langFunc zu reduzieren.



  • www.spam.geloescht



  • langFunc( boost::bind( &CMyClass::Meth1, &a, usw. ), .. weitere Parameter );

    was ist hier der input an boost::bind und was das output von boost::bind...zugleich der input an langFunc??!?



  • gasi schrieb:

    langFunc( boost::bind( &CMyClass::Meth1, &a, usw. ), .. weitere Parameter );

    was ist hier der input an boost::bind und was das output von boost::bind...zugleich der input an langFunc??!?

    Angenommen die Klasse CMyClass hat eine Methode Meth1, die einen int als Parameter aufnimmt.

    CMyClass::Meth1( int x );
    

    mit einem Aufruf von Meth1 wird das Objekt der Klasse CMyClass verändert, und genau das soll irgendwo innerhalb von langFunc geschehen. Dann gibt's die Möglichkeit, der Funktion langFunc eine Referenz oder einen Pointer auf das Objekt der Klasse CMyClass mitzugeben und langFunc ruft dann die Methode auf.

    void langFunc( CMyClass& a, ..Rest interesiert hier nicht )
        {
            // bla bla
            a.Meth1( x ); // <- hier wird's aufgerufen
    

    Damit ist die 'formale' Schnittstelle zwischen langFunc und CMyClass relativ breit. Der Aufrufer weiß gar nicht so recht, was da innerhalb von langFunc mit 'a' passiert.
    Nun gibt es die Möglichkeit, diesen Zugriff mittels eines Funktors (Foo s.u.) zu beschränken. Ausgeschrieben kann das so aussehen.

    struct Foo
    {
        explicit Foo( CMyClass& a ) : m_a( a ) {}
        void operator()( int x )
        {
            m_a.Meth1( x );
        }
    private:
        CMyClass& m_a;
    };
    
    // der Aufruf von langFunc passiert jetzt mit
        CMyClass a;
        langFunc( Foo( a ), ... ); // dem Foo-Objekt wird eine Referenz von a mitgegeben
    
    // und innerhalb des (jetzt als Template codierten) langFunc geschieht
        template< typename T >
        void langFunc( T f, ..Rest interesiert hier nicht )
        {
            // bla bla
            f( x ); // <- hier wird  a.Meth1( x ) aufgerufen
    

    Und damit man das alles (struct Foo s.o.) nicht selbst hinschreiben muss, kann man sich das von boost::bind generieren lassen. Der Ausdruck

    boost::bind( &CMyClass:.Meth1, &a, _1 );  // _1 steht als Platzhalter für den Parameter
    

    generiert genau so ein Funktor-Objekt wie Foo mit der Signatur void(*)( int ); dieser Funktor wird in langFunc aufgerufen und damit indirekt wieder die Methode Meth1 des Objekts 'a'. Der ganze Aufwand dient wie gesagt dazu, die Schnittstelle zu reduzieren und damit z.B. ganz konkret auch die Möglichkeit zu haben, von einem Objekt einer ganz anderen Klasse eine ganz andere Methode innerhalb von langFunc aufzurufen, und das ohne an langFunc eine Zeile zu ändern.

    .. Verwirrung perfekt 😉 ?
    Werner



  • Hmm gut, was nun - nur reine Geschmacksache?

    Ich verstehe das jetz so: Uebergibt man bei pass-by-reference nur eine Reference, sollte man diese als Funktionsparameter auch mit const deklarieren und hat dann eben auch die dementsprechenden Eigenschaften. Stoeren diese "const-Eigenschaften", sollte man stattdessen die Adresse uebergeben, muss aber eine etwaige Behandlung fuer null implementieren. Hab ich das richtig verstanden?

    Dann stellt sich fuer mich die Frage, ob es eben nicht auch Situationen/Faelle gibt, in denen eine Uebergabe MIT einer Reference OHNE const sinnvoll ist?

    returnTyp function( paramTyp &param)
    

    statt

    returnTyp function( const paramTyp &param)
    


  • [quote="Corcovado"]Hmm gut, was nun - nur reine Geschmacksache?[quote]
    jo.
    das problem ist, daß wegen der gut funktionierenden RVO es kaum noch fälle gibt, wo man nicht-const-referenzen oder zeiger als funktionsparameter benötigen würde. so richtig wenige fälle. eigentlich so wenige fälle, daß es egal ist.

    mir fällt folgender ein:

    template<typename T>
    class Lock{
    NOCOPY;
       private:
          T& object;
       public:
          Lock(T& o):
             object(o){
             o.lock();
          }
          ~Lock(){
             o.unlock();
          }
    };
    

    hier fühlt sich ne referenz irgendwie gescheiter an.

    würde ich einen vector füllen wollen und nicht auf RVO hoffen können, würde ich wohl einen zeiger nehmen.

    und nicht zu vergessen den lokale-referenz-trick:

    void collectThingies(vector<int>* result){
       assert(result!=0);
       vector<int>& r=*result;
       for(int i=0;i<100;++i)
          r.push_back(i*i%101);
       sort(r.begin(),r.end());
    }
    

    aber es kommt zu selten vor, ich habe keine meinung mehr zu diesem punkt.


Anmelden zum Antworten