C++ lambda copy beahaviour - c++

I wanted to undersatnd variable i scope w.r.to lambda function.
i is captured as by value So incrementation should only happen internally and it should not effect the global i value. So i expected output 1 1 1. But the output is 1 2 2
int i = 0;
auto a = [i]() mutable { cout << ++i << endl; };
a(); // i copies by value , So i value get changed internally in lambda function scope
auto b = a;
a(); // here why it is giving 2 instead of 1 ???
b();
What am i missing here ?

int i = 0;
auto a = [i]() mutable { cout << ++i << endl; }; // i is captured in a with value 0
a(); // i captured by a becomes 1
auto b = a; // b is copied from a, the captured i in b is copied with value 1 too
a(); // i captured by a becomes 2
b(); // i captured by b becomes 2

Result of lambda expression is an object with operator(). Code here
int i = 0;
auto a = [i]() mutable { cout << ++i << endl; };
a();
a();
results in behaviour roughly similar to this:
int i = 0;
struct local_lambda_01 {
private: // some older compilers skip this and in result there is an
// implementation detail that you can access following members
int i = ::i; // this is result of capture by value.
public:
void operator() { // it's not `const` because lambda is `mutable`
cout << ++i << endl; // it's `this->i`
}
} a; // a variable of local_lambda_01 type;
a(); // call to operator(), increments member i of local_lambda_01
a();
A copy of variable i's value was stored at point of creation of callable a instance. As lambda was declared mutable, operator() is not const-declared and can modify stored values. It doesn't change the original.
If we add statement
auto b = a;
after calling a(), we perform copy on already modified instance of the object.

Related

In C++ why is it when I reassign a reference variable to a different reference variable it creates a copy of that variable instead?

struct configfs
{
int & foo;
configfs(int & foo_) : foo(foo_) {}
void set_foo(int & foo_)
{
foo = foo_;
}
};
int main() {
int a = 1;
configfs conf(a);
a = 3;
std::cout << conf.foo; // 3
std::cout << a; // 3
int b = 2;
conf.set_foo(b);
b = 9;
std::cout << conf.foo; // 2
std::cout << b; // 9
return 0;
}
When I initialize configfs with int a and then alter a in the main function it also alters configfs.foo . But when I reassign configfs.foo to a new reference and alter that reference in the main function, the behavior is different. Why? Is there a way so that when I run conf.set_foo(b) and then alter b in the main scope, it also alters conf.foo as well?
When you wrote:
conf.set_foo(b);
The following things happen:
Member function set_foo is called on the object conf.
Moreover, the reference parameter named foo_ is bound the the argument named b. That is, b is passed by reference.
Next, the statement foo = foo_; is encountered. This is an assigment statement and not an initialization. What this does is that it assigns the value referred to by the parameter foo_ to the object referred to by the data member foo(which is nothing but a here). You can confirm this by adding std::cout<<a; after the call to set_foo as shown below:
int b = 2;
conf.set_foo(b);
std::cout<<a<<std::endl; //prints 2
This is because operations on a reference are actually operations on the object to which the reference is bound. This means that when we assign to a reference, we are assigning to the object to which the reference
is bound. When we fetch the value of a reference, we are really fetching the value of the object to which the reference is bound.
Note: Once initialized, a reference remains bound to its initial object. There is no way to rebind a reference to refer to a different
object.
Refercences can only be "assigned" during initialization. They cannot be "retargeted" the way like pointers. After the initialization the memory the reference refers to remains fixed and any assignment using = results in the invokation of the assignment operator to the memory the reference refers to. That's the way it's specified in the C++ standard.
You could rewrite the example using a custom type with assignment operators printing the information about calls:
template<class T>
struct configfs
{
T& foo;
configfs(T& foo_) : foo(foo_) {}
void set_foo(T& foo_)
{
foo = foo_; // this uses the assignment operator assigning to the variable foo is an alias for
}
};
// Type wrapping the int and printing out the operations applied
struct TestWrapper
{
TestWrapper(int value)
: value(value)
{
std::cout << "TestWrapper::TestWrapper(" << value << ")\n";
}
TestWrapper(TestWrapper const& other)
: value(other.value)
{
std::cout << "TestWrapper::TestWrapper(TestWrapper{" << other.value << "})\n";
}
TestWrapper& operator=(TestWrapper const& other)
{
std::cout << "TestWrapper::operator=(TestWrapper{" << other.value << "})\n";
value = other.value;
return *this;
}
int value;
};
std::ostream& operator<<(std::ostream& s, TestWrapper const& val)
{
s << val.value;
return s;
}
int main() {
TestWrapper a = 1;
configfs<TestWrapper> conf(a);
a = 3;
std::cout << conf.foo << '\n'; // 3
std::cout << a << '\n'; // 3
TestWrapper b = 2;
conf.set_foo(b); // TestWrapper::operator=(TestWrapper{2})
b = 9;
std::cout << conf.foo << '\n'; // 2
std::cout << b << '\n'; // 9
return 0;
}

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.

Pointer to class field as lambda argument

Why if we pass a class field pointer int* value in a lambda, then doesn't change value?
struct A {
A() {
auto f = [](int* value) {
value = new int(0);
};
f(value);
}
int* value = new int(42);
};
int main()
{
A obj{};
std::cout << *(obj.value) << std::endl;
}
Changes made to a function parameter are not visible to the caller, unless you take it by reference.
In your case, you would simply need to do
auto f = [](int* &value) {
value = new int(0);
};
Now changes to the parameter value are reflected in the member value.
Note that in your example, (without the reference), the compiler would warn that you are setting value but not using it.
Also, this might solve the specific question, but you are still leaking memory here.
your code isn't compilable - you cannot assign int* to int here: value = int(0);.
I have tried your code with fixed mentioned error:
struct A {
A() {
auto f = [](int* value) {
*value = int(0); // here value is being changed as expected
};
f(value);
}
int* value = new int(42);
};
int main()
{
A obj{};
std::cout << *(obj.value) << std::endl;
}
Everything works fine - passed value pointer to the f lambda is being changed from 42 to 0 value after constructor of struct is called.

Does capture by value in a C++ lambda expression require the value to be copied with the lambda object?

Does the standard define what happens with this code?
#include <iostream>
template <typename Func>
void callfunc(Func f)
{
::std::cout << "In callfunc.\n";
f();
}
template <typename Func>
void callfuncref(Func &f)
{
::std::cout << "In callfuncref.\n";
f();
}
int main()
{
int n = 10;
// n is captured by value, and the lambda expression is mutable so
// modifications to n are allowed inside the lambda block.
auto foo = [n]() mutable -> void {
::std::cout << "Before increment n == " << n << '\n';
++n;
::std::cout << "After increment n == " << n << '\n';
};
callfunc(foo);
callfunc(foo);
callfuncref(foo);
callfunc(foo);
return 0;
}
The output of this with g++ is:
$ ./a.out
In callfunc.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 10
After increment n == 11
In callfuncref.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 11
After increment n == 12
Are all features of this output required by the standard?
In particular it appears that if a copy of the lambda object is made, all of the captured values are also copied. But if the lambda object is passed by reference none of the captured values are copied. And no copies are made of a captured value just before the function is called, so mutations to the captured value are otherwise preserved between calls.
The type of the lambda is simply a class (n3290 §5.1.2/3), with an operator() which executes the body (/5), and an implicit copy constructor (/19), and capturing a variable by copy is equivalent to copy-initialize (/21) it to a non-static data member (/14) of this class, and each use of that variable is replaced by the corresponding data member (/17). After this transformation, the lambda expression becomes only an instance of this class, and the general rules of C++ follows.
That means, your code shall work in the same way as:
int main()
{
int n = 10;
class __Foo__ // §5.1.2/3
{
int __n__; // §5.1.2/14
public:
void operator()() // §5.1.2/5
{
std::cout << "Before increment n == " << __n__ << '\n';
++ __n__; // §5.1.2/17
std::cout << "After increment n == " << __n__ << '\n';
}
__Foo__() = delete;
__Foo__(int n) : __n__(n) {}
//__Foo__(const __Foo__&) = default; // §5.1.2/19
}
foo {n}; // §5.1.2/21
callfunc(foo);
callfunc(foo);
callfuncref(foo);
callfunc(foo);
}
And it is obvious what callfuncref does here.
I find it easiest to understand this behaviour by manually expanding the lambda to a struct/class, which would be more or less something like this (as n is captured by value, capture by reference would look a bit different):
class SomeTemp {
mutable int n;
public:
SomeTemp(int n) : n(n) {}
void operator()() const
{
::std::cout << "Before increment n == " << n << '\n';
++n;
::std::cout << "After increment n == " << n << '\n';
}
} foo(n);
Your functions callfunc and callfuncref operate more or less on objects of this type. Now let us examine the calls you do:
callfunc(foo);
Here you pass by value, so foo will be copied using the default copy constructor. The operations in callfunc will only affect the internal state of the copied value, no state changed in the actual foo object.
callfunc(foo);
Same stuff
callfuncref(foo);
Ah, here we pass foo by reference, so callfuncref (which calls operator()) will update the actual foo object, not a temporary copy. This will result in n of foo being updated to 11 afterwards, this is regular pass-by-reference behaviour. Therefore, when you call this again:
callfunc(foo);
You will again operate on a copy, but a copy of foo where n is set to 11. Which shows what you expect.
The value is captured by copy unless you explicitly capture-all [&] or capture a specific variable by reference [&n]. So the whole output is Standard.

C++ assignment on type cast

I stumbled upon something similar today, and subsequently tried a few things out and noticed that the following seems to be legal in G++:
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) { val_ = val; return *this; }
int get() { return val_; }
};
struct B : public A {
A getA() { return (((A)*this) = 20); } // legal?
};
int main() {
A a = 10;
B b;
A c = b.getA();
}
So B::getB returns a type A, after it as assigned the value 20 to itself (via the overloaded A::operator=).
After a few tests, it seems that it returns the correct value (c.get would return 20 as one may expect).
So I'm wondering, is this undefined behavior? If this is the case, what exactly makes it so? If not, what would be the advantages of such code?
After careful examination, with the help of #Kerrek SB and #Aaron McDaid, the following:
return (((A)*this) = 20);
...is like shorthand (yet obscure) syntax for:
A a(*this);
return a.operator=(20);
...or even better:
return A(*this) = 20;
...and is therefore defined behavior.
There are a number of quite separate things going on here. The code is valid, however you have made an incorrect assumption in your question. You said
"B::getA returns [...] , after it as assigned the value 20 to itself"
(my emphasis) This is not correct. getA does not modify the object. To verify this, you can simply place const in the method signature. I'll then fully explain.
A getA() const {
cout << this << " in getA() now" << endl;
return (((A)*this) = 20);
}
So what is going on here? Looking at my sample code (I've copied my transcript to the end of this answer):
A a = 10;
This declares an A with the constructor. Pretty straightfoward. This next line:
B b; b.val_ = 15;
B doesn't have any constructors, so I have to write directly to its val_ member (inherited from A).
Before we consider the next line, A c = b.getA();, we must very carefully consider the simpler expression:
b.getA();
This does not modify b, although it might superfically look like it does.
At the end, my sample code prints out the b.val_ and you see that it equals 15 still. It has not changed to 20. c.val_ has changed to 20 of course.
Look inside getA and you see (((A)*this) = 20). Let's break this down:
this // a pointer to the the variable 'b' in main(). It's of type B*
*this // a reference to 'b'. Of type B&
(A)*this // this copies into a new object of type A.
It's worth pausing here. If this was (A&)*this, or even *((A*)this), then it would be a simpler line. But it's (A)*this and therefore this creates a new object of type A and copies the relevant slice from b into it.
(Extra: You might ask how it can copy the slice in. We have a B& reference and we wish to create a new A. By default, the compiler creates a copy constructor A :: A (const A&). The compiler can use this because a reference B& can be naturally cast to a const A&.)
In particular this != &((A)*this). This might be a surprise to you. (Extra: On the other hand this == &((A&)*this) usually (depending on whether there are virtual methods))
Now that we have this new object, we can look at
((A)*this) = 20
This puts the number into this new value. This statement does not affect this->val_.
It would be an error to change getA such that it returned A&. First off, the return value of operator= is const A&, and therefore you can't return it as a A&. But even if you had const A& as the return type, this would be a reference to a temporary local variable created inside getA. It is undefined to return such things.
Finally, we can see that c will take this copy that is returned by value from getA
A c = b.getA();
That is why the current code, where getA returns the copy by value, is safe and well-defined.
== The full program ==
#include <iostream>
using namespace std;
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) {
cout << this << " in operator= now" << endl; // prove the operator= happens on a different object (the copy)
val_ = val;
return *this;
}
int get() { return val_; }
};
struct B : public A {
A getA() const {
cout << this << " in getA() now" << endl; // the address of b
return (((A)*this) = 20);
// The preceding line does four things:
// 1. Take the current object, *this
// 2. Copy a slice of it into a new temporary object of type A
// 3. Assign 20 to this temporary copy
// 4. Return this by value
} // legal? Yes
};
int main() {
A a = 10;
B b; b.val_ = 15;
A c = b.getA();
cout << b.get() << endl; // expect 15
cout << c.get() << endl; // expect 20
B* b2 = &b;
A a2 = *b2;
cout << b2->get() << endl; // expect 15
cout << a2.get() << endl; // expect 15
}