16

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?

3
  • 9
    It's not. One binds a pointer, the other binds a copy. Commented Apr 15, 2013 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. Commented Apr 15, 2013 at 15:01
  • duplicate:stackoverflow.com/questions/15264003/… Though I like both answers... Commented Nov 18, 2014 at 11:48

2 Answers 2

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);
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.