Using an std::function for wrapping a function object - c++

Can someone help me to understand why the following code causes an error?
class A
{
public:
float& operator()()
{
return _f;
}
private:
float _f = 1;
} a;
auto& foo()
{
std::function<float()> func = a;
return func();
}
int main()
{
std::cout << foo() << std::endl;
}
Error:
error: non-const lvalue reference to type 'float' cannot bind to a temporary of type 'float'
return func();
^~~~~~
1 error generated.
Here, in operator(), I return a reference to _fand consequently, I thought func() is not a temporary.
It would be great if someone helps me understand.

The problem isn't the use of std::function, its that you're trying to return the temporary float from func() as a reference.
This won't work since the object would cease to exist as soon as the statement ends.
If you change auto& foo() to auto foo() it should work.

I think you understand that returning a reference to a local variable isn't valid once the variable goes out of scope. What you seem to be missing though is that std::function<float()> func = a; actually creates a local std::function from a. It doesn't point to a in any way, func has it's own A. Which means that calling func(); doesn't actually invoke a.operator() but rather the A of func. Then we get back to the local variable returning a reference is evil part.
To make it compile, you can change your template signature to float&() but it's still undefined behaviour.
A fix would be to change the return type to a copy instead (to auto), removing the reference.

For std::function<float()> func, you're declaring func as a functor returning a float, not a float&. As the error message said, the temporary float returned by func() can't be bound to non-const lvalue reference.
The above declaration doesn't match the signature of A::operator() which being wrapped. But note that if change the type to std::function<float&()> func to match the signature of A::operator(), the compile error could be sovled, but then we'll return a reference bound to local variable, which leads to UB.
Note that for std::function<float()> func = a;, std::function is initialized with a copy of a. Then func() will return a reference bound to member of A wrapped in func, which is a local variable. And the reference will dangle when get out of function foo.
How to fix it depends on your design, change auto& foo() to auto foo(), i.e. passing the return value by copy would avoid UB here.

After reading the great answers above, I tried to give some different thoughts.
I guess OP really wants to return a float& of a certain object (which is a in OP's example).
So if OP wants foo to return auto& (which should be a float&), then it should be as the following, please note the std::bind part:
namespace T1
{
class A
{
public:
float& operator()()
{
std::cout << "a add = " << this << std::endl;
return _f;
}
float getF() { return _f; }
private:
float _f = 1;
} a;
auto& foo()
{
std::function<float&()> func = std::bind(&A::operator(), &a);
return func();
}
} // end of namespace T1
int main()
{
std::cout << "global a add = " << &(T1::a) << std::endl; // check a's address
float& f = T1::foo(); // note that `a`'s address is the same
std::cout << f << std::endl; // still 1
f = 777;
std::cout << f << std::endl; // now 777
std::cout << T1::a.getF() << std::endl; // it's 777
return 0;
}

Related

What is the point of returning a const alias from a function

Please look at the following code and help me understand:
Why the functionality to return a const alias to a literal like my f2 function exists. I don't understand what the point is.
The difference between f2 and f3 is that const does allow me to put a literal in the return statement, but again why?
Any help in understanding this is appreciated.
#include <iostream>
const int f1(int a)
{
return 15;
}
const int& f2(int a)
{
return 14;
}
int& f3(int a)
{
a = 12;
return a;
}
int main()
{
auto a{ 10 };
auto b = f1(a);
auto c = f2(a);
auto d = f3(a);
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3;
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
Both f2 and f3 have undefined behaviour. You are returning references to local variables. Those local variables are destroyed when the function ends, and the reference is dangling.
The difference between a const reference, and a non-const reference is that a const reference can bind to both rvalues and lvalues.
For non-const references you have to distinguish between lvalue-reference(int&) and rvalue-reference(int&&).
So using the function signature int&& f2(int a) would also compile, but equally have undefined behaviour.
The main reason this is usefull is because when we pass a reference to a function, the function signature tell us if we are expecting an lvalue or an rvalue. We can also overload both and decide to move/copy depending on what we get.
In the case where we don't care, or if we only want to read from the value we can use a const reference and be able to accept both lvalues and rvalues that are passed in.
void foo(MyClass& mc) {
// We know mc is an lvalue.
// We could copy mc, or modify it if we want to use it as an output parameter.
}
void foo(MyClass&& mc) {
// We know mc is an rvalue.
// We know it would be safe to move from mc in this case.
}
MyClass mc;
foo(mc); // Callsthe first overload
foo(MyClass{}); // Calls the second overload
// The two functions above can be overloaded, so we can make sure we deal
// with both cases in the right way
void foo2(const MyClass& mc) {
// This can be both an rvalue or lvalue.
// We don't really care since the reference
// is const we are only going to read from it.
}
foo2(mc); // Both calls work
foo2(MyClass{});
The b, c and d variables in main are initialized with a copy of what the functions return. No matter if they return a copy, a ref or a const ref.
To keep the attributes of the returned value, let's change the first lines in main:
int main()
{
auto a{ 10 };
auto& b = f1(a); // Does not compile, a ref can't be tied to a r-value
auto& c = f2(a); // Ok, c's type is 'const int&'
auto& d = f3(a); // Ok, d's type is 'int&'
std::cout << a << " " << b << " " << c << " " << d << std::endl;
a = 1;
b = 2;
c = 3; // Does not compile. c is a ref to a const
d = 4;
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
So, the point is you can return a reference to an internal variable, but now allowing the caller to change it. Doing so (instead of returning a copy), you
avoid the copy
allow the caller to see any later change
Not much sense for the code above, but think of a method inside a class, where the internal variable can be changed in other ways.
Besides the return type, f2 and f3 are not correct, as they return a reference to a not-in-memory (f2) or temporary object (f3).
Let's say you write a function that needs to return a complex object, but this object shouldn't be modified (such as pointer to a shared resource, class-property, some sort a singleton data and so on).
For the sake of this answer, lets assume the type in "struct Point".
You have 2 options to do so:
return it by value, which will create a deep copy of its primitive type members and a shallow copy of its by-reference-types members:
const struct Point f2(...)
return it by reference, which will copy only the pointer to the object:
const struct Point* f2()
const struct Point& f2()
both are valid, while the second one has the advantage when dealing with heavy objects.
In the code you provided you do not see the difference because "int" is a primitive type which means it has known way to be copied. This means var "c" isn't actually an alias nor a const, its an int who took its value from the return type of f2

How to pass a private member function as an argument

In ROS, there is a function called NodeHanle::subscribe(Args...): NodeHandle::subscribe. Which lets u pass a PRIVATE member function as callback.
However, when I tried it myself (passing private member function using std::bind), my compiler always fails and complaining about Foo::foo() is a private member function. When I change Foo::foo to public function, everything goes to normal.
template<typename T>
void getWrapper1(void(T::*fn)(int), T *t) {
return [&](int arg) {
std::cout << "process before function with wrapper" << std::endl;
(t->*fn)(arg);
std::cout << "process after function with wrapper" << std::endl;
};
}
void getWrapper2(std::function<void(int)> fn) {
return [=](int arg) {
std::cout << "process before function with wrapper" << std::endl;
fn(arg);
std::cout << "process after function with wrapper" << std::endl;
}
}
class Foo {
private:
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
}
int main(int argc, char** argv) {
Foo foo_inst;
auto func1 = getWrapper1(&Foo::foo, &foo_inst); // fail because foo is private
auto func2 = getWrapper2(std::bind(&Foo::foo, &foo_inst, std::placeholders::_1)); // fail because foo is private
func1(1);
func2(2);
return 0;
}
from this answer, using std::function can also passing private member function. But what I tried it different.
It worths to mention that in getWrapper2 I use [=] instead of [&] because using [&] may cause seg fault. Why it has to be a "value capture"?
platform: GCC 5.4.0, c++14, ubuntu16.04
You must pass it from the inside. You cannot access private function from the outside of the class. Not even pointer to private stuff. Private is private.
class Foo {
void foo(int a) {
std::cout << __FUNCTION__ << a << std::endl;
}
public:
auto getWrapper() {
// using a lambda (recommended)
return getWrapper2([this](int a) {
return foo(a);
});
// using a bind (less recommended)
return getWrapper2(std::bind(&Foo::foo, this, std::placeholders::_1));
}
}
Why it has to be a "value capture"?
Both wrapper need to value capture. Your Wrapper1 have undefined behaviour.
Consider this:
// returns a reference to int
auto test(int a) -> int& {
// we return the local variable 'a'
return a;
// a dies when returning
}
The same thing happen with a lambda:
auto test(int a) {
// we capture the local variable 'a'
return [&a]{};
// a dies when returning
}
auto l = test(1);
// l contain a captured reference to 'a', which is dead
Pointers are passed by value. A pointer is itself an object. A pointer has itself a lifetime and can die.
auto test(int* a) -> int*& {
// we are still returning a reference to local variable 'a'.
return a;
}
And... you guessed it, the same thing for std::function:
auto test(std::function<void(int)> a) {
// return a lambda capturing a reference to local variable 'a'.
return [&a]{};
}

const method modifies object using reference

The following code calls a const method passing a reference to a member, which is then modified.
#include <iostream>
struct A {
int i;
A(int _x) : i(_x) { }
void calc(int& j, const int value) const { j = value; }
void set1() { calc(i, 1); }
};
int main()
{
A a(3);
std::cout << a.i << std::endl;
a.set1();
std::cout << a.i << std::endl;
return 0;
}
The code compiles with gcc 6.4.0, and with clang 5.0.2, with no warnings.
Is the code legal?
The const method calc is able to modify the object, when called from a non-const method.
const qualifier on a member function applies to the *this instance.
In calc(), this is a pointer to const A, but the parameter j is taken by non-const reference, so this is perfectly standard behaviour.
Now, if in calc you tried to assign to this->i, the code would not compile.
void A::calc(const int value) const
{
i = value; // Compilation error here: i is a data member of a const instance
}
In the same way, if set1 was made a const member function, then, the code would not compile (because it would try to bind this->i to a parameter taken by non-const reference)
Sure. Marking the method const just makes *this const, i.e. the function promises not to modify the object by writing through this.
It's still possible to modify the object through other means (assuming they're not marked const as well, such as int& j in your example).
Remember that having a "const pointer" like const Thing* or a "const reference" like const Thing& does NOT mean that the const-qualified object cannot change while you have the pointer/reference. It only means that you can't use that particular pointer/reference as a way of changing it. But there could be other names, pointers, or references that do allow changing it.
A couple of examples:
void f1(const int& arg1, int& arg2) {
std::cout << "arg1 before: " << arg1 << "\n";
arg2 = 4;
std::cout << "arg1 after: " << arg1 << "\n"; // same thing?
}
f1 might look as though it must always print the same value in the "before" and "after" lines. But not if someone passes the same int object to both arguments:
void call_f1() {
int n = 7;
f1(n, n); // Prints before 7, after 4!
}
Or if a function call comes between two uses of a const reference, that can similarly change a variable in some way:
void something_else();
void f2(const int& arg) {
std::cout << "arg before: " << arg << "\n";
something_else();
std::cout << "arg after: " << arg << "\n";
}
int n = 2;
void something_else() { n = 8; }
void call_f2() {
f2(n); // Prints before 2, after 8!
}
So it's true that in your void A::calc(int& j, const int value) const function, the this pointer is const A* const, which means you can't change the A object using the this pointer. But there can still be other ways to change it, like here you have an int& j reference to non-const object. If it so happens that j refers to a subobject of *this, then modifying j is a valid way of modifying the subobject of *this. This is similar to my f1 example above, where arg1 can't be used to change the referenced int, but arg2 can, and if they refer to the same int, this means arg1 has changed.
The case is slightly different when a variable is defined with the const qualifier in the first place. If we write
const A a(3);
then we do get a guarantee that (except during the constructor and destructor), the object can't be changed in any way. The language will usually prevent you from accidentally trying, like with a.set1(), but even if you try const_cast tricks, any actual change would then be undefined behavior.
There is nothing wrong with your code. Declaring a method const merely means that this is const. However, your method does not (directly) modify this or any members of this. Consider this contrived, albeit correct example:
struct foo {
int value;
void modify_const(foo& f) const { f.value = 5; }
};
int main() {
foo f;
f.value = 3;
f.modify_const(f);
}
The method does not modify this, and the parameter is declared as non-const, thus calling f.modify_const(f); on a const f will fail due to the parameter being passed as non-const.
Just shows you are never safe. A const qualifier doesn't guarantee the value can never change.
Try it like this, and you can do really nasty things:
#include <iostream>
class A {
const int i;
void calc(int& j, const int value) const { j = value; }
public:
A(int _x) : i(_x) { }
void set1() const { calc(*const_cast<int*>(&i), 1); }
int getI() const { return i; }
};
int main()
{
const A a(3);
std::cout << a.getI() << std::endl;
a.set1();
std::cout << a.getI() << std::endl;
return 0;
}

Const reference to R value

In C++ it is valid to use take a const reference to a temporary:
const std::string& s = std::string("abc");
std::cout << s.length() << std::endl; // valid because string instance is still alive
But does this hold true if the temporary was created via a conversion from another type?
For example:
struct Foo
{
~Foo()
{
cout << "Foo destructor?" << endl;
}
};
struct Bar
{
operator Foo()
{
return Foo();
}
~Bar()
{
cout << "Destructor" << endl;
}
};
Foo getFoo()
{
return Foo();
}
Bar getBar()
{
return Bar();
}
int main()
{
const Foo& f = getBar();
/* is f valid here, or is it a dangling reference? */
std::cout << "We're still in main!" << std::endl;
}
I note that Bar's destructor is called before We're still in main is output, which makes me think that Foo& f is a dangling reference. Am I correct?
It does not matter how the temporary was created. If you bind a const X& or an X&& to a local prvalue, the lifetime of the temporary gets extended to the lifetime of the reference.
The function getBar creates an object of type Bar and immediately destroys returning a copy of it.
Bar getBar()
{
return Bar();//the lifetime of Bar() is only on this line;
}
Edit:
For the question in the source code if const Foo & f is valid; yes it is because getBar returns an object copy.
Also after checking the code i see that it first returns a copy of Bar and then casts it to Foo
Also i must mention the RVO (from the comments section) which is an optimization from the compiler. The lifetime of the object is still defined by it's scope {} however in this case the construction is done inside the function and the destruction is outside the function. This optimization will not work of you give a name to the variable like such:
Bar getBar()
{
Bar tmp_value;
return tmp_value;
}
Razvan.

The constness of a variable and its lifetime

So from a question asked in another thread, I have thought of a new question and the answer is not obvious to me.
So it appears there is a c++ rule that says if you have a const reference to a temporary, then the lifetime of the temporary is at least as long as the const reference. But what if you have a local const reference to another object's member variable and then when you leave scope - Does it call the destructor of that variable?
So here is modified program from the original question:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(std::string l) { k = l; };
std::string get() const { return k; };
std::string k;
};
class B {
public:
B(A a) : a(a) {}
void b() { cout << a.get(); } //Has a member function
A a;
};
void f(const A& a)
{ //Gets a reference to the member function creates a const reference
stores it and goes out of scope
const A& temp = a;
cout << "Within f(): " << temp.k << "\n";
}
int main() {
B b(A("hey"));
cout << "Before f(): " << b.a<< "\n";
f(b.a);
cout << "After f(): " << b.a.k << "\n";
return 0;
}
So when I run this code, I get "hey" as the value everytime. Which seems to imply that a local const reference does not bind itself through life with a passed in member object. Why doesn't it?
b.a is not a temporary so its lifetime is not affected by any references that are subsequently bound to it.
I'm not sure I understand what you're asking. In your code, the only
temporary I see is the A("hey") in the expression that initializes b
in main. And that is copied (using the copy constructor) into b.a
in B::B. After that, there are no more temporaries, anywhere.
More generally, the fact that a temporary is bound to a reference
doesn't necessarily change its lifetime. What extends the lifetime is
the fact that the temporary is used to initialize the reference: in your
case, for example, temp in f will never have an effect on the
lifetime of a temporary, because it is not initialized with a temporary,
but with another reference. And there are exceptions to this rule: if
you use a temporary to initialize a member reference in the initializers
of a class, it's lifetime will still not extend beyond the end of the
constructor, so:
class A
{
std::string const& rString;
public:
A() : rString( std::string( "hey" ) ) {}
std::string get() const { retur rString; }
};
will not work.