在 C++ 中,堆栈展开后指针是否仍然有效?
5 回答
这取决于指向对象的存储。如果该对象是堆栈分配的,那么指针肯定会变得无效 - 堆栈展开将正确地破坏该对象。如果对象是堆分配的,则只有在堆栈展开期间存在一些释放对象的 RAII 变量时,指针才会变为无效。
这取决于你的指针指向什么。如果它指向堆内存,它仍然有效。如果它指向堆栈内存,它将变得无效。
不,随着堆栈展开,在堆栈未展开部分的范围内声明的所有变量/指针都会被销毁。
此外,该规则考虑Storage Type
了变量的 。
例如:static
变量在函数调用之间保留其值,这意味着它在堆栈展开期间不会被破坏。这是因为静态变量不存储在堆栈上,而是存储在 BSS 或数据段上。
Local variables
在函数内部的堆栈上创建的( Auto storage type
) 将始终在函数返回和堆栈展开发生时被销毁。
在堆上分配内存的指针不会在堆栈展开时被销毁,因为它们是在堆上分配而不是在堆栈上分配的。
要记住的一个重要规则是永远不要在函数内返回指针或对局部变量的引用。指针或引用将包含垃圾值。
考虑一些例子:
void* f1a()
{
void* p = malloc(10);
return p;
}
...是相同的...
void* f1b()
{
return malloc(10);
}
这很好,因为指针指向堆,因此独立于堆栈、函数调用和程序范围。指针值在函数返回时被复制。
int* f2()
{
int x;
return &x; // pointer to x - about to become invalid!
}
上面返回一个指向栈上变量的指针,函数返回时x
会回收(丢失)。x
只是说一件我觉得很重要的额外事情
说我们有这个声明
obj* objptr = new obj(9) //allocate memory on heap and use constructor
如果这里发生异常..内存堆被重新释放......即没有内存泄漏......
原因是......不是因为堆栈展开......而是因为新运算符转换为以下生成代码的方式,try catch语句在新运算符中实现......像这样......
void * operator new(size_t s)
{
try
{
void * ptr=new(malloc (s))sample(); //placement new
ptr->...
}
catch(..)
{
operator delete(ptr); //<= notice here so if an exception occur then first it is caught here which releases the memory
}
}
但是,如果在对象内完成了一些内存分配,但仍然没有被释放..