可能重复:
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:返回本地变量的地址或 临时
答案 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)
如果要返回数组或指针,则有两条路径。
一条路线:新
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会来找你......)。