非法删除堆栈对象[重复]

Posted

技术标签:

【中文标题】非法删除堆栈对象[重复]【英文标题】:Illegal deletion of a stack object [duplicate] 【发布时间】:2013-08-03 17:38:05 【问题描述】:
int main()

    myClass obj;

    ....    /* doing things */
    ....

    delete &obj; /* illegal */

让我们假设 myClass 是一个适当的 C++ 类,一切都已就绪。现在,我知道这是非法的,这个程序会在运行时崩溃。第一件事是代码试图删除一个堆栈对象,然后在范围完成后再次删除它。我想知道这个非法操作的内部情况。即删除会发生什么,它会调用析构函数吗?你可能看起来很疯狂,但请帮助我理解。

【问题讨论】:

它会可能崩溃,但与未定义行为的情况一样,另一方面,它可能不会崩溃,或者大多数时间但并非总是崩溃,或者甚至导致nasal demons。更重要的是你的问题,真的没有办法告诉这将如何处理,未定义行为的性质在大多数情况下是不可预测的。 通过检查非优化构建中生成的代码,不难发现它的实际作用 这不是骗子。这里的 OP 不是问它是否安全,他们知道它不安全。 @jrok 该线程的答案仍然 100% 适用于这个问题:这是未定义的行为。 【参考方案1】:

你错过了一件重要的事情——除了调用析构函数之外,delete 将释放分配给new 的内存并将其返回到堆中。在堆栈分配的变量上调用 free 是不安全的。要查看它是否会首先调用析构函数,只需将一些 cout 放入 myClass 析构函数 - 在我的配置中它在分段错误之前调用析构函数。

#include <iostream>

using namespace std;

class myClass

 public:
     ~myClass() cout << "Destructor" << endl; 

;


int main()

        myClass A;
        delete &A;
        cout << "End of main\n";
        return 0;

来自MSDN:

当 delete 用于为 C++ 类对象释放内存时,在释放对象内存之前调用对象的析构函数(如果对象具有析构函数)。

【讨论】:

【参考方案2】:

经验法则:

对于每个new,应该恰好有一个delete。 对于每个new[],应该恰好有一个delete[]。 对于每个malloccalloc,应该恰好有一个free。 对于每个 stack allocated 对象,不应有任何显式删除。

其他任何事情都会导致未定义的行为

即删除会发生什么,它会调用析构函数吗?

是的,delete会先调用对象的析构函数。

【讨论】:

【参考方案3】:

行为未定义。会发生什么将取决于类的细节、发生了什么、程序的内存管理器是如何实现的、您使用的编译器、您正在运行的系统,以及可能还有许多其他我没有做的事情花时间去想。这很像询问化学品储罐爆炸时会发生什么的细节。

【讨论】:

【参考方案4】:

这是未定义的行为。标准,我们所有人赖以生存和尊重的话语,它说:

否则,提供给运算符 delete(void*) 的值 标准库应是前一个返回的值之一 调用 operator new(size_t) 或 operator new(size_t, 标准库中的 const std::nothrow_t&)

所以这是未定义的行为,任何事情都可能发生,这取决于被错误删除的对象的实现、编译器、运气和其他因素。在内部询问“发生了什么”是没有意义的,因为任何事情都可能发生。最有可能的是,由于 delete 运算符假定您正确使用它,您最终会在堆栈中引入一些不可预测的更改,这可能会搞砸任何事情。也许你之前的帧指针被覆盖,也许一些荒谬的返回值被推送到一个函数,也许保存的寄存器被覆盖,所以尝试恢复寄存器状态会导致非常非法的情况。不管发生什么,都是丑陋的。

【讨论】:

以上是关于非法删除堆栈对象[重复]的主要内容,如果未能解决你的问题,请参考以下文章

非法尝试在不同上下文中的对象之间建立关系“对象”

CUDA 中大小为 4 的非法写入

如何修复php非法偏移错误[重复]

休眠异常缺少信息:非法尝试将集合与两个打开的会话相关联

对空结果集的非法操作[重复]

删除非法字符的助手?