我遇到了一些C ++范围问题,但我无法弄清楚原因。通过公开一切,我从原始问题中简化了很多。有人可以帮我理解为什么vec在main结束时为空?如何让Get1stVec(...)实际将vec设置为不会立即销毁的东西?
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;
}
答案 0 :(得分:2)
void Get1stVec(Polygon* poly, Vec2* vec)
修改vec
的本地副本,而不是vec
中的变量main
。它们是不同的变量。
你可以传递一个引用,或者重新设计并删除所有那些无用的指针。
答案 1 :(得分:1)
我修改了您的Get1stVec
签名。您正在尝试修改本地指针vec
。因此 地址已传递给函数以获得有效修改。如果main中的vec
指针已经开始有一些地址,那么早期的声明就会起作用。
#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;
}
答案 2 :(得分:0)
函数参数是其局部变量。它们由提供的参数的副本初始化。
你可以想象这个功能
<div id="ced"></div>
及其电话
void Get1stVec(Polygon* poly, Vec2* vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
以下方式(我重命名了与参数不同的参数)
Get1stVec(&poly, vec);
当你看到它是被改变的参数而不是参数。
如果您希望在函数中更改参数,则应通过引用传递参数。
例如
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;
^^^^
}
答案 3 :(得分:0)
我在代码中看到两个问题。 vec
函数中的_tmain()
不会更改此示例中的值。它是nullptr
,因为您将其初始化为nullptr
。
了解原因。我们必须检查Get1stVec
:
void Get1stVec(Polygon* poly, Vec2* vec)
{
Vec2* tmp = &poly->verts.at(0); // tmp gets a valid pointer here.
vec = tmp;
}
注意:在Get1stVec
中,可以访问vec(如果它是有效的)指针并取消引用它。这是nullptr
,访问或取消引用会导致访问冲突。
poly->verts.at(0);
会从Vec2
返回verts vector
的副本。正如我们在Get1stVec
函数中一样,该副本是在堆栈上创建的。
注意:只有在执行函数时才堆栈变量和对象生命。传递给函数的参数值也是如此。这同样适用于本地定义的变量和对象。
所以
Vec2* tmp = &poly->verts.at(0);
tmp是一个本地定义的指针,存在于堆栈中。 poly->verts.at(0);
的结果也存在于堆栈中。
现在
poly->verts.at(0);
vec = tmp;
已分配。 vec
是一个传递的参数,它也存在于堆栈中。
当代码执行离开Get1stVec
时,堆栈将被展开并且所有信息都将丢失。
如果要保存堆栈展开的信息,请使用对Get1stVec
指针的引用传递,如下所示:
Get1stVec(Polygon* poly, Vec2&* vec)
参数vec
现在引用vec
函数中的_tmain
指针,而不是堆栈。
答案 4 :(得分:0)
您正在通过值将Vec2
指针传递给Get1stVec
。换句话说,您正在函数内部执行指针的复制。如果您将该本地指针修改为指向其他位置,则不会更改main
函数中的指针。
您可以通过引用Vec2*&
传递指针,但是通过Get1stVec
的值返回指针会更加惯用。在这种情况下,指针不能为null,因此返回引用而不是指针会更好:
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?
}
我还更改Get1stVec
以引用Polygon
而不是指针。