Reputation: 1149
I'm running into some C++ scoping problems, and I can't figure out why. I've simplified this a lot from the original problem by making everything public. Can someone help me understand why vec is null at the end of main? How do I get Get1stVec(...) to actually set vec to something which doesn't get immediately destroyed?
class Vec2
{
public:
float x, y;
Vec2(float x_, float y_) : x(x_), y(y_) {}
Vec2() : x(0.0f), y(0.0f) {}
};
class Polygon
{
public:
void AddVertex(Vec2 vert) { verts.push_back(vert); }
std::vector<Vec2> verts;
};
void Get1stVec(Polygon* poly, Vec2* vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
int _tmain(int argc, _TCHAR* argv[])
{
Polygon poly;
poly.AddVertex(Vec2(1.0f, 1.0f));
Vec2* vec = nullptr;
Get1stVec(&poly, vec);
vec->x = 2.0f; // vec is nullptr here. Why?
return 0;
}
Upvotes: 1
Views: 81
Reputation: 15334
You are passing the Vec2
pointer to Get1stVec
by value. In other words, you are taking a copy of the pointer inside the function. If you modify that local pointer to point at something else it will not change the pointer in the main
function.
You could pass the pointer by reference Vec2*&
but it would be more idiomatic to return the pointer by value from Get1stVec
. In this case the pointer cannot be null so it would be even better to return a reference instead of a pointer:
Vec2& Get1stVec(Polygon& poly)
{
return poly.verts.at(0);
}
int main()
{
Polygon poly;
poly.AddVertex(Vec2(1.0f, 1.0f));
Vec2& vec = Get1stVec(poly);
vec.x = 2.0f; // vec is nullptr here. Why?
}
I've also changed Get1stVec
to take Polygon
by reference instead of pointer.
Upvotes: 0
Reputation: 538
I see two issues in the code. vec
in the _tmain()
function will not change the value in this example. It is a nullptr
because you initialized it as a nullptr
.
To understand why. we have to examine Get1stVec
:
void Get1stVec(Polygon* poly, Vec2* vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
Note: In Get1stVec
it is possible to access the vec (if it is valid) pointer and dereference it. Here it is a nullptr
, to accessing or dereferencing would lead to an access violation.
poly->verts.at(0);
will return a copy of Vec2
from the verts vector
. As we are in the Get1stVec
function, that copy is created on the stack.
Note: Stack variables and object life only as long as the function is executed. So do the passed parameter values to the function. The same applies to locally defined variables and objects.
So
Vec2* tmp = &poly->verts.at(0);
tmp is a locally defined pointer and lives on the stack. The result of poly->verts.at(0);
lives also on the stack.
Now
poly->verts.at(0);
vec = tmp;
is assigned. vec
is a passed parameter, it lives also on the stack.
When the code execution leaves Get1stVec
, the stack will be unwind and all information is lost.
If you want to save the information of the stack unwind, then using pass a reference to your pointer to Get1stVec
like this:
Get1stVec(Polygon* poly, Vec2&* vec)
parameter vec
is now referencing a pointer to vec
in the _tmain
function and not the stack.
Upvotes: 0
Reputation: 2449
I have modified your Get1stVec
signature. You are trying to modify the local pointer vec
. So its address has be passed to function to get a valid modification. The earlier declaration would have worked if the vec
pointer in main already had some address to begin with.
#include <iostream>
#include <vector>
class Vec2
{
public:
float x, y;
Vec2(float x_, float y_) : x(x_), y(y_) {}
Vec2() : x(0.0f), y(0.0f) {}
};
class Polygon
{
public:
void AddVertex(Vec2 vert) { verts.push_back(vert); }
std::vector<Vec2> verts;
};
void Get1stVec(Polygon* poly, Vec2** vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
*vec = tmp;
}
int main()
{
Polygon poly;
poly.AddVertex(Vec2(1.0f, 1.0f));
Vec2* vec = nullptr;
Get1stVec(&poly, &vec); //passing address of the vec pointer
vec->x = 2.0f; // vec is nullptr here. Why? - **Look at previous line**
return 0;
}
Upvotes: 1
Reputation: 310990
Function parameters are its local variables. They are initialized by copies of the supplied arguments.
You can imagine this function
void Get1stVec(Polygon* poly, Vec2* vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
and its call
Get1stVec(&poly, vec);
the following way (I renamed parameters that they would differ from arguments)
void Get1stVec(/*Polygon* poly1, Vec2* vec1*/)
{
Polygon* poly1 = &poly;
Vec2* vec1 = vec;
Vec2* tmp = &poly1->verts.at(0); // tmp gets a valid pointer here.
vec1 = tmp;
^^^^
}
As you cann see it is the parameter that was changed not the argument.
You should pass an argument by reference if you want that it would be changed in a function.
For example
void Get1stVec(Polygon* poly, Vec2* &vec )
^^^^
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
Upvotes: 0
Reputation: 50063
void Get1stVec(Polygon* poly, Vec2* vec)
modifies the local copy of vec
, not the variable vec
you have in your main
. They're different variables.
You may pass a reference instead or alternatively redesign and get rid of all those useless pointers.
Upvotes: 2