2013-04-15 11 views
7

mam ten kod:std :: wiążą z funkcji członka klasy

#include <iostream> 
#include <functional> 

struct Foo 
{ 
     int get(int n) { return 5+n; } 
}; 

int main() 
{ 
     Foo foo; 
     auto L = std::bind(&Foo::get, &foo, 3); 

     std::cout << L() << std::endl; 

     return 0; 
} 

Wydaje się, że w ten sposób:

auto L = std::bind(&Foo::get, &foo, 3); 

jest equivalento do:

auto L = std::bind(&Foo::get, foo, 3); 

Dlaczego?

+8

To nie jest. Jeden wiąże wskaźnik, drugi wiąże * kopię *. – Xeo

+1

Dla tego, co jest warte, możesz także przekazać inteligentny wskaźnik (dowolny typ, który implementuje 'operator->', aby zwrócić 'foo *') jako drugi argument. Wypróbuj go za pomocą 'std :: shared_ptr'. –

+0

duplikat: http: //stackoverflow.com/questions/15264003/using-stdbind- with-member-function-use-object-pointer- or-not-for-this-argumen Chociaż lubię obie odpowiedzi ... – nephewtom

Odpowiedz

14

std::bind() przyjmuje argumenty według wartości. Oznacza to, że w pierwszym przypadku podajesz wskaźnik po wartości, co powoduje skopiowanie wskaźnika. W drugim przypadku przekazujesz obiekt typu foo według wartości, co daje kopię obiektu typu Foo.

W konsekwencji, w drugim przypadku oceny ekspresji L() wywołuje funkcję składową get() się powoływać na kopii oryginalnego obiektu foo, które mogą lub nie mogą być, co chcesz.

Ten przykład ilustruje różnicę (zapomnieć o naruszenie Reguły trzy/Reguły Piątki, to tylko w celach ilustracyjnych):

#include <iostream> 
#include <functional> 

struct Foo 
{ 
    int _x; 

    Foo(int x) : _x(x) { } 

    Foo(Foo const& f) : _x(f._x) 
    { 
     std::cout << "Foo(Foo const&)" << std::endl; 
    } 

    int get(int n) { return _x + n; } 
}; 

int main() 
{ 
    Foo foo1(42); 

    std::cout << "=== FIRST CALL ===" << std::endl; 
    auto L1 = std::bind(&Foo::get, foo1, 3); 
    foo1._x = 1729; 
    std::cout << L1() << std::endl; // Prints 45 

    Foo foo2(42); 

    std::cout << "=== SECOND CALL ===" << std::endl; 
    auto L2 = std::bind(&Foo::get, &foo2, 3); 
    foo2._x = 1729; 
    std::cout << L2() << std::endl; // Prints 1732 
} 

Live example.

Jeśli z jakiegokolwiek powodu nie chcesz, aby skorzystać z formularza wskaźnika, można użyć std::ref() aby zapobiec kopii argumentu z tworzonej:

auto L = std::bind(&Foo::get, std::ref(foo), 3); 
3

To nie to samo. Ta funkcja generuje argumenty. W przypadku std::bind(&Foo::get,&foo,3), wskaźnik jest kopiowany, ale po wywołaniu związanego obiektu nadal odnosi się do oryginalnego obiektu foo. W obiekcie std::bind(&Foo::get,foo,3) jest kopiowany obiekt foo, a późniejsze wywołanie odnosi się do oprawionej kopii, a nie do oryginalnego obiektu.

Można to przetestować za pomocą funkcji składowej, która uzyskuje dostęp do wewnętrznego stanu obiektu, wiąże obiekt w obie strony, zmienia oryginalny obiekt i sprawdza, jak wyniki się różnią.

Powiązane problemy