类局部变量的指针

Pointer of class local variable?

本文关键字:指针 局部变量      更新时间:2023-10-16

可能重复:
可以使用局部变量';内存是否在其范围之外被访问?

做这样的代码(getIDs((返回指针(有什么令人担忧的事情吗:

class Worker{
private:
    int workerID;
    int departID;
    int supervisorID;
public:
    Worker() 
    {
        workerID=0;
        departID=0;
        supervisorID=0;
        name="anonymous";
        workerAddress="none";
    }
    void setIDs(int worker, int depart, int supervisor)
    {
        workerID=worker;
        departID=depart;
        supervisorID=supervisor;
    }
    int* getIDs()
    {
        int id[3];
        id[0]=workerID;
        id[1]=departID;
        id[2]=supervisorID;
        return id;
    }
};

然后,这样使用它:

Worker obj;
obj.setIDs(11,22,33);
cout<<(*obj.getIDs())<<endl;
cout<<++(*obj.getIDs())<<endl;
cout<<++(++(*obj.getIDs()))<<endl;

我想知道这一点,因为编译器显示:

警告1警告C4172:返回本地变量或的地址临时

您的int id[3]在堆栈上分配,并在int* getIDs()返回时被销毁。

返回一个指向变量的指针,该变量在getIDs()返回后立即被销毁。指针然后变得悬空,实际上是无用的,因为用它做任何事情都是未定义的行为。

假设你这样定义你的类:

class Worker{
private:
    int IDs[3];
public
    // ...
    int* getIDs() { return IDs; }
};

这个部分地解决了您的问题,因为只要Worker对象在作用域中,指针就会保持有效,但这仍然是一种糟糕的做法。示例:

int* ptr;
while (true) {
    Worker obj;
    obj.setIDs(11,22,33);
    ptr = obj.getIDs();
    cout << *ptr;   // ok, obj is still alive.
    break;
}  // obj gets destroyed here
cout << *ptr;   // NOT ok, dereferencing a dangling pointer

解决此问题的更好方法是实现您的自定义运算符<lt;为你的班级。类似这样的东西:

class Worker {
private:
    int workerID;
    int departID;
    int supervisorID;
public:
    // ...
    friend ostream& operator<<(ostream& out, Worker w);
};

ostream& operator<<(ostream& out, const Worker& w)
{
    out << w.workerID << "n" << w.departID << "n" << w.supervisorID;
    return out;
}

即使这样做有效,在c++中这样做也不是一个好的做法,除非你想要指向int的指针有一些深刻的原因。原始c样式数组比std::vectors更难处理,所以使用它们,比如

std::vector<int> getIDs(){
  std::vector<int> id(3);
  id[0]=workerID; id[1]=departID; id[2]=supervisorID;
  return id;
}

如果你担心开销:这可能会被现代编译器完全优化掉。

一旦离开定义局部变量的函数,它就会被销毁。所以你的指针会指向这个被破坏的位置,当然在函数外引用这样的位置是不正确的,会导致未定义的行为。

这里的基本问题是,当您输入一个函数调用时,您会在堆栈上获得一个新的框架(所有本地变量都将保存在其中(。任何未在函数中动态分配(使用new/malloc(的内容都将存在于该堆栈帧中,并且在函数返回时会被销毁。

函数返回一个指针,指向您在即将消失的堆栈帧中声明的3元素数组的开头。因此,这是未定义的行为

虽然你可能会感到"幸运/不幸运",但当你使用指针时,你的数据仍然在指针指向的地方,但你也可能会遇到相反的情况。由于堆栈帧被破坏时会放弃空间,因此可以重用它,因此代码的另一部分可能会使用存储该数组中三个元素的内存位置,这意味着当您取消引用该指针时,它们将具有完全不同的值。

如果你运气好的话,你的程序只会出错/崩溃,所以你知道你犯了一个错误。

重新设计你的函数,以返回一个3 int的结构,一个向量,或者至少(我不建议这样做(,用new动态分配数组内容,这样它在函数调用后仍然存在(但你最好稍后删除它,否则小妖精会来找你…(。

编辑:很抱歉,我完全误解了这个问题。我喝咖啡之前不应该回答StackOverflow。

当您想要返回一个数组,或者更确切地说是一个指针时,有两个路由。

一条路线:新

int* n = new int[3];
n[0] = 0;
// etc..
return n;

由于n现在是一个堆对象,以后由您删除它,如果您不删除它,最终会导致内存泄漏。

现在,我发现第二条路线是一种更容易的方法,但风险更大。它是您传入数组并在中复制值的地方。

void copyIDs(int arr[3] /* or int* arr */)
{
    arr[0] = workerID;
    /* etc */
}

现在您的数组已经填充,并且没有堆分配,所以没有问题。

编辑:将局部变量作为地址返回是错误的。为什么?

给定函数:

int* foo() { 
    int x = 5;
    return &x; // Returns the address (in memory) of x
} // At this point, however, x is popped off the stack, so its address is undefined
  // (Garbage)  
// So here's our code calling it
int *x = foo(); // points to the garbage memory, might still contain the values we need
// But what if I go ahead and do this?
int bar[100];        // Pushed onto the stack
bool flag = true;    // Pushed onto the stack
std::cout << *x << 'n'; // Is this guaranteed to be the value we expect?

总的来说,风险太大。不要这样做。