std::bind of class member function - c++

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?

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);

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.

Related

Overwriting object with new object of same type and using closure using this

In the following code an object is overwritten with a new object of same type, where a lambda-expression creates a closure that uses this of the old object. The old address (this) remains the same, the new object has the same layout, so this should be ok and not UB. But what about non trivial objects or other cases?
struct A {
void g(A& o, int v) {
o = A{.x = v, .f = [this]{
std::cout << "f" << this->x << '\n';
}};
}
int x{0};
std::function<void()> f;
~A() {
std::cout << "dtor" << x << '\n';
}
};
void test() {
A a;
a.g(a, 2);
a.f();
}
You are not actually replacing any object. You are just assigning from another object to the current one. o = simply calls the implicit copy assignment operator which will copy-assign the individual members from the temporary A constructed in the assignment expression with A{...}.
The lambda is going to capture this from this in g, not from the temporary object.
std::function will always keep a copy of the lambda referring to the original object on which g was called and since that is its parent object, it cannot outlive it.
So there is no problem here. The only exception would be that you call f during the destruction of the A object, in which case using the captured pointer may be forbidden.
Here is a slightly modified code with a corner case. I create a temporary in a function and call g on it passing it a more permanent object. The temporary vanishes and the long life object now has a closure refering to an object after its end of life. Invoking f is UB:
#include <iostream>
#include <functional>
struct A {
void g(A& o, int v) {
o = A{ .x = v, .f = [this] {
std::cout << "f" << this->x << ' ' << this << '\n';
} };
}
int x{ 0 };
std::function<void()> f;
~A() {
std::cout << "dtor" << x << ' ' << this << '\n';
}
};
void test(A& a) {
A b{ 2 };
b.g(a, 3);
}
int main() {
A a{ 1 };
std::cout << a.x << '\n';
test(a);
std::cout << a.x << '\n';
a.f(); // UB because a.f uses an object after its end of life
}
The output is:
1
dtor3 0135F9C0
dtor2 0135FA30
3
f341072 0135FA30
dtor3 0135FAA8
proving that the invocation of a.f() tried to use the object at address 0135FA30 (in that specific run) after it has been destroyed.

Using auto in lambda function declaration

When can auto be used as the type specifier of a variable initialized with a lambda function? I'm try to use auto in the following program:
#include <iostream>
#include <functional>
class A
{
const std::function <void ()>* m_Lambda = nullptr;
public:
A(const std::function <void ()>& lambda): m_Lambda (&lambda) {}
void ExecuteLambda()
{
(*m_Lambda)();
}
};
void main()
{
int i1 = 1;
int i2 = 2;
const auto lambda = [&]()
{
std::cout << "i1 == " << i1 << std::endl;
std::cout << "i2 == " << i2 << std::endl;
};
A a(lambda);
a.ExecuteLambda();
}
I'm using Visual Studio Community 2019 and when I start executing a.ExecuteLambda(), the program stops with the following exception:
Unhandled exception at 0x76D9B5B2 in lambda.exe:
Microsoft C ++ exception: std :: bad_function_call at memory location 0x00B5F434.
If I change the line const auto lambda = [&]() to const std::function <void ()> lambda = [&](), it works perfectly. Why is it not allowed to use auto? Can something be changed to allow it to be used?
A lambda expression does not result in a std::function. Instead, it creates an unnamed unique class type and that has an overload for operator(). When you pass your lambda to A's constructor, it creates a temporary std::function object, and you store a pointer to that temporary object. When A's constructor ends, that temporary object is destroyed, leaving you with a dangling pointer.
To fix this, just get rid of using pointers. That would look like
#include <iostream>
#include <functional>
class A
{
std::function <void ()> m_Lambda;
public:
A(const std::function <void ()> lambda): m_Lambda (lambda) {}
void ExecuteLambda()
{
m_Lambda();
}
};
void main()
{
int i1 = 1;
int i2 = 2;
const auto lambda = [&]()
{
std::cout << "i1 == " << i1 << std::endl;
std::cout << "i2 == " << i2 << std::endl;
};
A a(lambda);
a.ExecuteLambda();
}
You are storing a dangling std::function pointer in your A object.
A lambda expression is not a std::function object, it is a compiler-defined type that is assignable to a std::function object.
When you declare lambda using auto, it gets a unique type. To bind this lambda to the A constructor's parameter, a temporary std::function object is created, which you are storing a pointer to. But then, that temporary gets destroyed when the constructor exits, which is why you get the exception when you try to execute the std::function.
When you change the declaration of lambda to std::function instead, the A constructor's parameter is able to bind to that object as-is, and no temporary is created.
You should be passing and storing std::function objects by value instead of by pointer, eg:
#include <iostream>
#include <functional>
class A
{
std::function<void()> m_Lambda;
public:
A(std::function<void()> lambda): m_Lambda(lambda) {}
void ExecuteLambda()
{
m_Lambda();
}
};
int main()
{
int i1 = 1;
int i2 = 2;
const auto lambda = [&]()
{
std::cout << "i1 == " << i1 << std::endl;
std::cout << "i2 == " << i2 << std::endl;
};
A a(lambda);
a.ExecuteLambda();
return 0;
}
Online Demo

Did std::bind implement std::ref and std::cref to disambiguate the function call?

I know that I shouldn't overload a function for just parameters differ only in one of them passed by copy and the other by reference:
void foo(int x)
{
cout << "in foo(int x) x: " << x << endl;
}
void foo(int& x)
{
cout << "in foo(int& x) x: " << x << endl;
}
int main()
{
int a = 1;
foo(5); // ok as long as there is one best match foo(int)
foo(a); // error: two best candidates so the call is ambiguous
//foo(std::move(a));
//foo(std::ref(an)); // why also this doesn't work?
}
So a code that uses std::bind can be like this:
std::ostream& printVec(std::ostream& out, const std::vector<int> v)
{
for (auto i : v)
out << i << ", ";
return out;
}
int main()
{
//auto func = std::bind(std::cout, std::placeholders::_1); // error: stream objects cannot be passed by value
auto func = std::bind(std::ref(std::cout), std::placeholders::_1); // ok.
}
So std::ref here to ensure passing by reference rather than by value to avoid ambiguity?
* The thing that matters me: Does std::bind() implemented some wrapper to overcome this issue?
Why I can't use std::ref in my example to help the compiler in function matching?
Now that you know passing by value and reference are ambiguous when overload resolution tries to compare them for choosing a best viable function, let's answer how would you use std::ref (or std::cref) to differentiate between pass-by-value and pass-by-reference.
It turns out to be ... pretty simple. Just write the overloads such that one accepts a int, and the other accepts a std::reference_wrapper<int>:
#include <functional>
#include <iostream>
void foo(int x) {
std::cout << "Passed by value.\n";
}
void foo(std::reference_wrapper<int> x) {
std::cout << "Passed by reference.\n";
int& ref_x = x;
ref_x = 42;
/* Do whatever you want with ref_x. */
}
int main() {
int x = 0;
foo(x);
foo(std::ref(x));
std::cout << x << "\n";
return 0;
}
Output:
Passed by value.
Passed by reference.
42
The function pass the argument by value by default. If you want to pass by reference, use std::ref explicitly.
Now let's answer your second question: how does std::bind deal with this type of scenario. Here is a simple demo I have created:
#include <functional>
#include <type_traits>
#include <iostream>
template <typename T>
struct Storage {
T data;
};
template <typename T>
struct unwrap_reference {
using type = T;
};
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> {
using type = std::add_lvalue_reference_t<T>;
};
template <typename T>
using transform_to_storage_type = Storage<typename unwrap_reference<std::decay_t<T>>::type>;
template <typename T>
auto make_storage(T&& obj) -> transform_to_storage_type<T> {
return transform_to_storage_type<T> { std::forward<T>(obj) };
}
int main() {
int a = 0, b = 0, c = 0;
auto storage_a = make_storage(a);
auto storage_b = make_storage(std::ref(b));
auto storage_c = make_storage(std::cref(c));
storage_a.data = 42;
storage_b.data = 42;
// storage_c.data = 42; // Compile error: Cannot modify const.
// 0 42 0
std::cout << a << " " << b << " " << c << "\n";
return 0;
}
It is not std::bind, but the method used is similar (it's also similar to std::make_tuple, which has the same semantic). make_storage by default copies the parameter, unless you explicitly use std::ref.
As you can see, std::ref is not magic. You need to do something extra for it to work, which in our case is to first decay the type (all references are removed in this process), and then check whether the final type is a reference_wrapper or not; if it is, unwrap it.

How does a std::function object which return a std::function work when call by operator()?

Sample:
#include "stdafx.h"
#include <functional>
#include <iostream>
#include <string>
std::function<void(int)> Foo()
{
int v = 1;
int r = 2;
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
return l;
}
int main()
{
auto func = Foo();
func(3);
return 0;
}
Why func(3) can pass 3 to i which is the formal argument of the lambda in Foo(). I can't think out. thanks.
TL;DR: You don't pass your argument 3 into a function Foo. You pass it to a method of an object func.
A bit more detailed explanation is below.
First of all, I would like to clarify what a lambda is. A lambda in C++ is nothing more than an anonymous functor class, so essentially just a syntactic sugar. A closure is an instance of a lambda type. However, quite often you can hear words "lambda" and "closure" being used interchangeably.
So within your function Foo() you create a closure object l
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
which would be technically equivalent to this code:
struct Functor
{
Functor(int v, int r) : v_(v), r_(r) {}
void operator ()(int i) const {
std::cout << v_ << " " << r_ << " " << i << std::endl;
}
private:
int v_;
int r_;
};
Functor l(v, r);
Now, on the next line you return an std::function object.
return l; // actually creates std::function<void(int)>(l) and returns it
So in your main function a func is just an object which stores copies of values v, r obtained during a call to Foo() and defines operator(), similar to the struct above.
Therefore, calling func(3) you actually invoke an object method on a concrete object func, and without syntactic sugar it looks like func.operator()(3).
Here's a live example to illustrate my point.
Hope that helps to resolve your confusion.

How to initialize `std::function` with a member-function?

I am trying to learn std::function and here's my code:
#include <iostream>
#include <functional>
struct Foo {
void print_add(int i){
std::cout << i << '\n';
}
};
typedef std::function<void(int)> fp;
void test(fp my_func)
{
my_func(5);
}
int main(){
Foo foo;
test(foo.print_add);
return 0;
}
Compiler Error:
error: cannot convert 'Foo::print_add' from type 'void (Foo::)(int)' to type 'fp {aka std::function<void(int)>}'
test(foo.print_add);
How can I make this work, i.e how can I pass a member function as a parameter?
print_add is a non-static member function of foo, which means it must be invoked on an instance of Foo; hence it has an implicit first argument, the this pointer.
Use a lambda that captures the foo instance and invokes print_add on it.
Foo foo;
test([&foo](int i){ foo.print_add(i); });
Another option is to use std::bind to bind the foo instance:
test(std::bind(&Foo::print_add, &foo, std::placeholders::_1));
Live demo
You need an object to call a non-static member function. Hence, when you want to get a std::function you have several options:
make the method static
bind an object to the function via lambda
store the object in the std::function
pass the object when the std::function is called
#include <iostream>
#include <functional>
struct A {
int i = 42;
int get() const { return i; }
static int get_static() { return 0; }
};
struct A_functor {
A a;
int operator()() const { return a.get(); }
};
int main() {
// static method
std::function<int()> f1 = &A::get_static;
std::cout << f1() << "\n";
// bind an object to the function via lambda
A a;
std::function<int()> f2 = [&a](){ return a.get(); };
std::cout << f2() << "\n";
// store the object in the std::function
std::function<int()> f3 = A_functor{};
std::cout << f3() << "\n";
// or
std::function<int()> f4 = [a = A()](){ return a.get(); };
std::cout << f4() << "\n";
// pass the object when the std::function is called
std::function<int(A&)> f5 = &A::get;
std::cout << f5(a) << "\n";
// or
std::function<int(A*)> f6 = &A::get;
std::cout << f6(&a) << "\n";
}
THE PROBLEM
You cannot directly bind a member-function pointer belonging to type Foo to std::function<void(int)>, specifically because calling a non-static member-function requires an instance of type Foo.
Foo obj; obj.member_function (); // can't call `member_function` without `obj`
Note: You can however bind &Foo::print_add to std::function<void(Foo&, int)> x;, and call it as x(instance_of_Foo, arg);.
Note: It's also possible to bind it to std::function<void(Foo*, int>, which would require a Foo* instead of an lvalue of type Foo.
THE SOLUTION
Instead you can use std::bind to bind an instance of Foo to the member-function in question, such as in the below example:
int main(){
Foo foo;
test (std::bind (&Foo::print_add, foo, std::placeholders::_1));
return 0;
}
Above we bind an instance of Foo named foo to the member-function pointer &Foo::print_add.
The usage of std::placeholders::_1 tells std::bind that we'd like it to generate a function-object that is callable using one (1) argument.
With the above snippet you will have the behaviour that you are currently asking for; my_func(5) will be equivalent of calling foo.print_add (5).
DOCUMENTATION
std::function - cppreference.com
std::bind - cppreference.com
std::placeholders - cppreference.com