2011-12-01 53 views
4

可能重复:
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

这不是真的重复 - 在这个问题上,海报明白他们在做什么不应该工作,并且为什么它工作困惑。在这个问题中,海报想要知道这是否会起作用。 – Justin

回答

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 

解决这个更好的办法是实现您的自定义操作< <为你的类。就像这样:

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

int id[3]被分配在栈上,并得到毁坏了,当你int* getIDs()回报。

1

一旦你离开函数定义的地方,一个本地(也是caled自动)变量就会被销毁。所以你的指针会指向这个被破坏的位置,当然在函数之外引用这样一个位置是不合适的,并且会导致未定义的行为。

2

即使这会起作用,在C++中这样做并不是一个好习惯,除非有一些深刻的原因让你指向int。原C-SYLE阵列更难以处理比,例如,std::vector S,所以使用那些像

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

如果你担心的开销:这很可能是由现代编译器完全优化掉。

+0

@:使用static int id [3];可以解决吗? – Aan

+0

@Adban,因为没有人回答你,我会的。是的,静态会有所帮助。但问题是如果静态真的是你想要的。 *通常*静态用于保存功能的一些内部数据。在这里,你只是想计算并返回一些东西。 – Beginner

+0

可能吗?我们怎样才能依靠可能?我不会*复制*像这样的矢量... – Beginner

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? 

总体而言,这是太冒险了。不要这样做。

1

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

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

尽管您可能会得到“幸运/不幸”,并且仍然将数据放在指针所指向的位置,但您也可能会在此代码中发生相反的情况。由于堆栈框架被破坏时空间被放弃,所以它可以被重用 - 所以你的代码的另一部分可能会使用存储该数组中三个元素的内存位置,这意味着它们可能会有完全不同的值你解除指针的时间。

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

重新设计你的函数返回3个整数,一个向量的结构,或者至少(我不建议这样做),动态地分配数组内容,所以它在函数调用后仍然存在(但你更好地删除它,或者gremlins会来,让你......)。