I am reading through the C++ lambda section in chapter 3 of this book and the following code confuses me:
int x = 0;
int y = 42;
auto qqq = [x, &y] {
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
++y;
};
x = y = 77;
qqq();
qqq();
std::cout << "final y: " << y << std::endl;
This code prints out:
x: 0
y: 77
x: 0
y: 78
final y: 79
Why does qqq() not register that x has changed to 77? It was stated that passing by value means we can read but not modify data readable where the lambda was defined. Does that mean we can't see changes after it's definition?
That's because the variable is captured by value (i.e. copied) only once, when you define the lambda. It's not "updated" as you may believe. The code is roughly equivalent to:
#include <iostream>
int x = 0;
struct Lambda
{
int _internal_x; // this is used to "capture" x ONLY ONCE
Lambda(): _internal_x(x) {} // we "capture" it at construction, no updates after
void operator()() const
{
std::cout << _internal_x << std::endl;
}
} qqq;
int main()
{
qqq();
x = 77; // this has no effect on the internal state of the lambda
qqq();
}
Live on Coliru
By binding a variable by value to a lambda closure, you're effectively copying the value of the variable into a separate variable that is found inside the lambda object. Likewise, by binding a variable by reference, you're making such an internal variable to be a reference to the original variable instead, thus being able to "see changes" on the original variable.
Look at it like this. The following code...
#include <iostream>
int main()
{
int x = 0;
int y = 42;
auto qqq = [x, &y] {
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
++y;
};
x = y = 77;
qqq();
qqq();
std::cout << "final y: " << y << std::endl;
}
Is (kind of, but not exactly) syntactic sugar for...
#include <iostream>
class MyLambda
{
private:
int x;
int& y;
public:
MyLambda(int x, int& y) : x(x), y(y) {}
void operator()()
{
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
++y;
}
};
int main()
{
int x = 0;
int y = 42;
MyLambda qqq = MyLambda(x, y);
x = y = 77;
qqq();
qqq();
std::cout << "final y: " << y << std::endl;
}
With the exception of the special lambda syntax and the fact that you can't reference the lambda's type directly. By comparing the former with the later code, you should be able to clear out your understanding of closures.
The lambda uses the value at the time the lambda is defined (it makes a copy), not at the time it is invoked.
This might help: How are Lambda Closures Implemented?
Related
I am learning C++ and I have code:
float x, y;
namespace X {
void SetMyX(float p) {
x = p;
}
void SetMyY(float p) {
y = p;
}
namespace XY {
void Set(float p = 0.0f) {
x = p;
p = y;
}
}
}
int main() {
X::SetMyX(5.4f);
std::cout << "x = " << x << " y = " << y << std::endl;
X::SetMyY(4.1f);
std::cout << "x = " << x << " y = " << y << std::endl;
X::XY::Set();
std::cout << "x = " << x << " y = " << y << std::endl;
return 0;
}
And output is:
x = 5.4 y = 0
x = 5.4 y = 4.1
x = 0 y = 4.1
And I figure out variable p sets value of x and then y sets value of p? But, how it is possible? In C++ you can also set value of function's argument or what?
It's just weird for me because I thought you can't just "editing" entered value and you must add another variable like result or something like that, or just return sum of two arguments, but change them?
Yes, the argument p is a completely normal variable and you can do everything with it.
This will also work in many other languages like C, Java, Javascript or Python.
I'm trying to change a parameter of an object inside an array, but it seems like it's creating a new one when I pass it to the function.
I already saw similar questions and answers like this one, but it doesn't work for me, because I don't have a fixed array size in the final code.
I created a very short version of the code to show the problem.
#include <iostream>
using namespace std;
class Vect {
public:
Vect(int x, int y)
{
_x = x;
_y = y;
}
int _x;
int _y;
};
void ChangeX(Vect tests[], int size)
{
for (int i = 0; i < size; i++) {
tests[i]._x = 39;
}
}
int main()
{
Vect v1 = Vect(1,2);
Vect v2 = Vect(6,3);
cout << "Initial X: ";
cout << v1._x;
cout << "\n";
Vect vectors[2] = { v1, v2 };
cout << "Final X: ";
ChangeX(vectors, 2);
cout << v1._x;
return 0;
}
I expect the output to be:
Initial X: 1
Final X: 39
But in reality is:
Initial X: 1
Final X: 1
Also, using C++ vectors is not the solution for now. I'm running low on program memory usage and have a very small space for extra code.
Your issue has nothing to do with your function. It is updating the contents of the array correctly. There is no need to pass the array itself by reference.
The real problem is with the array itself. The statement Vect vectors[2] = {v1, v2}; makes copies of the v1 and v2 objects in the array. Your function is modifying the copies, and then afterwards you output values from the originals instead of the copies. So, your output does not change, since the function is not modifying the originals.
To accomplish what you are attempting, pass in an array of pointers instead, where the pointers are pointing at the original objects, not copies of them, eg:
#include <iostream>
class Vect {
public:
Vect(int x, int y){
_x = x;
_y = y;
};
int _x;
int _y;
};
void ChangeX(Vect* tests[], int size){
for(int i = 0; i < size; i++){
tests[i]->_x = 39;
}
}
int main()
{
Vect v1(1,2);
Vect v2(6,3);
std::cout << "Initial X:\n";
std::cout << v1._x << "\n";
std::cout << v2._x << "\n";
Vect* vectors[2] = {&v1, &v2};
ChangeX(vectors, 2);
std::cout << "Final X:\n";
std::cout << v1._x << "\n";
std::cout << v2._x << "\n";
return 0;
}
Live Demo
Otherwise, start out with an array to begin with, eg:
#include <iostream>
class Vect {
public:
Vect(int x, int y){
_x = x;
_y = y;
};
int _x;
int _y;
};
void ChangeX(Vect tests[], int size){
for(int i = 0; i < size; i++){
tests[i]._x = 39;
}
}
int main()
{
Vect vectors[2] = {Vect(1,2), Vect(6,3)};
std::cout << "Initial X:\n";
std::cout << vectors[0]._x << "\n";
std::cout << vectors[1]._x << "\n";
ChangeX(vectors, 2);
std::cout << "Final X:\n";
std::cout << vectors[0]._x << "\n";
std::cout << vectors[1]._x << "\n";
return 0;
}
Live Demo
I'm fairly new to C++, and I'm experiencing some issues when printing local and global variables. Consider this simple piece of code:
#include <cstdlib>
#include <iostream>
using namespace std;
/*
*
*/
int x = 10; // This x is global
int main() {
int n;
{ // The pair of braces introduces a scope
int m = 10; // The variable m is only accessible within the scope
cout << m << "\n";
int x = 25; // This local variable x hides the global x
int y = ::x; // y = 10, ::x refers to the global variable x
cout << "Global: " << y << "\n" << "Local: " << x << "\n";
{
int z = x; // z = 25; x is taken from the previous scope
int x = 28; // it hides local variable x = 25 above
int t = ::x; // t = 10, ::x refers to the global variable x
cout << "(in scope, before assignment) t = " << t << "\n";
t = x; // t = 38, treated as a local variableout was not declared in this scope
cout << "This is another hidden scope! \n";
cout << "z = " << z << "\n";
cout << "x = " << x << "\n";
cout << "(in scope, after re assignment) t = " << t << "\n";
}
int z = x; // z = 25, has the same scope as y
cout << "Same scope of y. Look at code! z = " << z;
}
//i = m; // Gives an error, since m is only accessible WITHIN the scope
int m = 20; // This is OK, since it defines a NEW VARIABLE m
cout << m;
return 0;
}
My goal is practicing the accessibility of the variables within the various scopes, and then printing them. However, I'm not able to figure out why when I try to print the last variable z, NetBeans gives me back the output 2025.
Here it follows my sample output:
10
Global: 10
Local: 25
(in scope, before assignment) t = 10
This is another hidden scope!
z = 25
x = 28
(in scope, after re assignment) t = 28
Same scope of y. Look at code! z = 2520
RUN FINISHED; exit value 0; real time: 0ms; user: 0ms; system: 0ms
Hope that somebody can help me understanding what is going on! :)
is not that z is holding the value 2520 is the fact that you ommit to add a new line operator between printing z and printing m...
you are doing:
cout << "Same scope of y. Look at code! z = " << z;
}
int m = 20;
cout << m;
but you should do:
std::cout << "Same scope of y. Look at code! z = " << z << std::endl;
}
int m = 20;
std::cout << m << std::endl;
if you just followed the same criteria of labeling the output and doing something like
std::cout << "M is: "<<m << std::endl;
you would spotted the issue faster by observing the output:
25M is: 20
I feel like an idiot. When I pass a variable to the function it results in a strange output like 6.2+e003 instead of the value that the variable holds. What am I doing wrong?
The x in main and the x in the function are different?
main:
int x, y;
while(system.WindowOpen())
{
x++;
y++;
bg.Draw2D();
bob.Think(x, y);
riley.Think(x, y);
system.Render(0);
}
class method:
void Organism::Think(double x, double y)
{
std::cout << "X: " << x << "\n";
std::vector<double> food;
food.push_back(x);
food.push_back(y);
std::cout << "VECTOR: " << food[0] << " " << food[1] << "\n";
std::vector<double> path;
if(refresh.IsTime()) {
std::cout << "\nFOOD VECTOR: \n" << food[0]
<< "\n" << food[1] << "\n";
path = brian.GetOutput(food);
organism.Translate2D(path[0], path[1]);
if(organism.IsOffScreen2D(resX, resY) == 'l' )
organism.SetPos2D(resX, organism.GetY());
if(organism.IsOffScreen2D(resX, resY) == 'r')
organism.SetPos2D(0, organism.GetY());
if(organism.IsOffScreen2D(resX, resY) == 't')
organism.SetPos2D(organism.GetX(), resY);
if(organism.IsOffScreen2D(resX, resY) == 'b')
organism.SetPos2D(organism.GetX(), 0);
};
font.DrawNumber2D(x, 50, 50);
font.DrawNumber2D(y, 50, 100);
organism.Draw2D();
}
Both x and y are uninitialized here:
int x, y;
so they can hold any value, and reading from them is undefined behaviour. You should initialize them:
int x = 0
int y = 0;
I was writing outside the bounds of a vector. I switched from using the [] operators to using the .at() and found my bug right away. Just a bit of memory corruption. I feel quite silly. Thanks all!
Is it possible to convert the is_const expressions into a test function or is this impossible because top level cv-qualifieres are ignored during template type deduction?
int main()
{
using std::is_const;
const int x = 0;
int y = 0;
// move to "bool test()"
std::cout
<< "main, x: " << is_const<decltype(x)>::value << "\n" // true
<< "main, y: " << is_const<decltype(y)>::value << "\n" // false
;
std::cout
<< "test, x: " << test(x) << "\n" // false, I wanted true
<< "test, y: " << test(y) << "\n" // false
;
}
I have unsuccessfully tried various versions similar to:
template<typename T>
bool test(T x)
{
return is_const<???>::value;
}
I want to make sure that I am not missing something and that writing such a testfunction is indeed impossible. (If it was possible, I would also like to know whether a C++03 version was possible.)
Thank you for your consideration
Update
Due to Mankarse I learned that type deduction is different in case of rvalue references:
template<typename T> void t1(T x);
template<typename T> void t2(T& x);
template<typename T> void t3(T&& x);
const int x = 42;
int y = 0;
t1(x); // T = int: t1<int>(int x)
t1(y); // T = int: t1<int>(int x)
t2(x); // T = const int: t2<const int>(const int& x)
t2(y); // T = int: t2<int>(int& x)
t3(x); // T = const int&: t3<const int&>(const int& && x)
t3(y); // T = int&: t3<int&>(int& && x)
In C++11, this can be done with perfect forwarding rvalue references:
template<typename T>
bool test(T&& x)
{
return std::is_const<typename std::remove_reference<T>::type>::value;
}
In C++03, you can instead use an lvalue reference:
template<typename T>
bool test(T& x) {
return boost::is_const<T>::value;
}
The differences between the two are demonstrated below:
typedef int const intc;
intc x = intc();
int y = int();
std::cout // C++11 C++03
<< "x: " << test(x) << "\n" // 1 1
<< "y: " << test(y) << "\n" // 0 0
<< "move(x): " << test(std::move(x)) << "\n"// 1 1 (when compiled as C++11)
<< "move(y): " << test(std::move(y)) << "\n"// 0 compilation error
<< "intc{}: " << test(intc()) << "\n" // 0 compilation error
<< "int{}: " << test(int()) << "\n" // 0 compilation error
;