Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::bind of class member function

Tags:

c++

c++11

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?

like image 622
Gian Lorenzo Meocci Avatar asked Apr 15 '13 13:04

Gian Lorenzo Meocci


People also ask

What is the use of std :: bind?

std::bind. The function template bind generates a forwarding call wrapper for f . Calling this wrapper is equivalent to invoking f with some of its arguments bound to args .

What does bind function do in C++?

Bind function with the help of placeholders helps to manipulate the position and number of values to be used by the function and modifies the function according to the desired output. What are placeholders? Placeholders are namespaces that direct the position of a value in a function.

Does STD bind allocate?

The std::bind will be copied into heap allocated by the std::function and the std::function will be copied into heap allocated by the std::vector .

What is the return type of std :: bind?

std::bind return type The return type of std::bind holds a member object of type std::decay<F>::type constructed from std::forward<F>(f), and one object per each of args... , of type std::decay<Arg_i>::type, similarly constructed from std::forward<Arg_i>(arg_i).


1 Answers

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);
like image 134
Andy Prowl Avatar answered Sep 18 '22 06:09

Andy Prowl