C ++指针范围问题

时间:2015-11-05 18:33:36

标签: c++ pointers vector

我遇到了一些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;
}

5 个答案:

答案 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而不是指针。

Live demo