类局部变量的指针?

时间:2011-12-01 12:59:07

标签: c++ class pointers

  

可能重复:
  Can a local variable's memory be accessed outside its scope?

做代码是否令人担忧(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:返回本地变量的地址或   临时

6 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

即使这样可行,但在c ++中这样做也不是一个好习惯,除非你有一些深刻的理由要求指向int。原始的c-syle数组比std::vector更难处理,所以使用它们,比如

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

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

答案 2 :(得分:2)

您将返回指向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;&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;
}

答案 3 :(得分:1)

一旦离开定义它的函数,本地(也称为自动)变量就会被销毁。所以你的指针将指向这个被破坏的位置,当然,引用函数外部的这样一个位置是incorect并将导致未定义的行为。

答案 4 :(得分:1)

编辑:道歉,我完全误解了这个问题。我不应该在喝咖啡之前回答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?

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

答案 5 :(得分:1)

这里的基本问题是,当你输入一个函数调用时,你会在你的堆栈上得到一个新的框架(所有的局部变量都将被保存)。在你的函数中没有动态分配的任何东西(使用new / malloc)将存在于那个堆栈框架中,当你的函数返回时它会被销毁。

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

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

如果你很幸运,你的程序只会出现故障/崩溃,所以你知道你犯了错误。

重新设计你的函数以返回3个int的结构,一个向量,或者至少(我不推荐这个),用new动态分配数组内容,这样它在函数调用后仍然存在(但你最好稍后删除它或者gremlins会来找你......)。