14

I have this code:

#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;
}

Seems that this:

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

is equivalento to:

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

Why?

billz
  • 44,644
  • 9
  • 83
  • 100
Gian Lorenzo Meocci
  • 1,136
  • 2
  • 14
  • 23
  • 8
    It's not. One binds a pointer, the other binds a *copy*. – Xeo Apr 15 '13 at 13:16
  • 1
    For what it's worth, you can also pass a smart pointer (any type that implements `operator->` to return a `foo*`) as the second argument. Try it with a `std::shared_ptr`. – Pete Becker Apr 15 '13 at 15:01
  • duplicate:http://stackoverflow.com/questions/15264003/using-stdbind-with-member-function-use-object-pointer-or-not-for-this-argumen Though I like both answers... – nephewtom Nov 18 '14 at 11:48

2 Answers2

23

std::bind() accepts its arguments by value. This means that in the first case you are passing a pointer by value, resulting in the copy of a pointer. In the second case, you are passing an object of type foo by value, resulting in a copy of an object of type Foo.

As a consequence, in the second case the evaluation of the expression L() causes the member function get() to be invoked on a copy of the original object foo, which may or may not be what you want.

This example illustrates the difference (forget the violation of the Rule of Three/Rule of Five, this is just for illustration purposes):

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

If, for any reason, you don't want to use the pointer form, you can use std::ref() to prevent a copy of the argument from being created:

auto L = std::bind(&Foo::get, std::ref(foo), 3);
anilbey
  • 1,817
  • 4
  • 22
  • 38
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
4

They are not the same. The generic function binder std::bind copies it's arguments. In the case of std::bind(&Foo::get,&foo,3), the pointer is copied, but when you call the bound object it still applies to the original foo object. In std::bind(&Foo::get,foo,3) the object foo is copied, and the later call applies to the bound copy, not to the original object.

You can test this by using a member function that accesses internal state of the object, bind the object in both ways, change the original object and see how the results differ.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489