C++ 为什么悬空指针延迟会使程序崩溃

C++ 为什么悬空指针延迟会使程序崩溃,c++,c,pointers,memory,memory-management,C++,C,Pointers,Memory,Memory Management,我听过很多次,悬空的指针反引用会使程序崩溃,但我不知道为什么。谁能给我解释一下吗 据我所知,在C/C++中,当我们通过指针p释放内存对象o后,p成为指向语义无效的内存地址addr的悬空指针。可能稍后内存分配器会将addr重新分配给另一个内存对象。不管这种情况发生与否,OS将考虑 ADDR 仍然是一个合法的访问地址,因为内存分配器只请求来自OS的内存,而从不将内存返回给OS。所以根本不应该发生撞车。谁能告诉我我的理解错在哪里 无论发生与否,操作系统都会考虑ADDR仍然是访问的合法地址。 不,事实并

我听过很多次,悬空的指针反引用会使程序崩溃,但我不知道为什么。谁能给我解释一下吗

据我所知,在C/C++中,当我们通过指针
p
释放内存对象
o
后,
p
成为指向语义无效的内存地址
addr
的悬空指针。可能稍后内存分配器会将
addr
重新分配给另一个内存对象。不管这种情况发生与否,OS将考虑<代码> ADDR 仍然是一个合法的访问地址,因为内存分配器只请求来自OS的内存,而从不将内存返回给OS。所以根本不应该发生撞车。谁能告诉我我的理解错在哪里

无论发生与否,操作系统都会考虑ADDR仍然是访问

的合法地址。 不,事实并非如此,恰恰相反。一旦您
free()
内存,无论它是否实际释放,访问(甚至再次尝试
free()
都被视为非法

正如每一次非法内存访问都会导致调用一样,这样做的副作用是分段错误

无论发生与否,操作系统都会考虑ADDR仍然是访问

的合法地址。 不,事实并非如此,恰恰相反。一旦您
free()
内存,无论它是否实际释放,访问(甚至再次尝试
free()
都被视为非法


由于每一次非法内存访问都会导致调用,因此也会导致调用,其副作用是分段错误。

悬空指针可以指向任何东西,有时程序可能会继续 因为它得到的值似乎是正确的,这可能会传播多次 直到出现故障或更糟的情况

foo *bar = malloc(sizeof(foo));
void * dangling = &bar;
free(bar);
悬挂现在指的是什么?或者将堆栈分配的结构作为 指针式ie

char * foo() {
  char string[10] = "Boom";
  return string;
}   
基本上,程序无法检测正在使用的项目是否有效 在使用之前,有时甚至在使用时,它仍然无法检测到它。按照严重程度的顺序,检测可能发生如下情况

  • 编译器发现一个双空闲或返回对堆栈分配对象的引用。或者您试图释放一个它从未实际分配的对象

  • 操作系统发现您正试图访问在进程地址空间之外分配的内存,即访问冲突/分段故障/总线错误等

  • 你的程序开始运行异常,最终会崩溃,或者有人重新启动你的应用程序,或者内存不足等等


  • 在我的例子中,您的分配器ie malloc可以从区域分配内存,即预先分配的内存块,它有开始和结束地址。任何释放这些范围之外的区域的请求都是错误的,在这种情况下,您可能会遇到分段错误。这是分配器可以检测到的一个错误,它无法检测到您引用了随后被释放的内存区域,即现在是垃圾。然后你尝试使用垃圾,结果造成混乱。

    一个悬空的指针可以指向任何东西,有时程序可能会继续 因为它得到的值似乎是正确的,这可能会传播多次 直到出现故障或更糟的情况

    foo *bar = malloc(sizeof(foo));
    void * dangling = &bar;
    free(bar);
    
    悬挂现在指的是什么?或者将堆栈分配的结构作为 指针式ie

    char * foo() {
      char string[10] = "Boom";
      return string;
    }   
    
    基本上,程序无法检测正在使用的项目是否有效 在使用之前,有时甚至在使用时,它仍然无法检测到它。按照严重程度的顺序,检测可能发生如下情况

  • 编译器发现一个双空闲或返回对堆栈分配对象的引用。或者您试图释放一个它从未实际分配的对象

  • 操作系统发现您正试图访问在进程地址空间之外分配的内存,即访问冲突/分段故障/总线错误等

  • 你的程序开始运行异常,最终会崩溃,或者有人重新启动你的应用程序,或者内存不足等等


  • 在我的例子中,您的分配器ie malloc可以从区域分配内存,即预先分配的内存块,它有开始和结束地址。任何释放这些范围之外的区域的请求都是错误的,在这种情况下,您可能会遇到分段错误。这是分配器可以检测到的一个错误,它无法检测到您引用了随后被释放的内存区域,即现在是垃圾。然后你尝试使用垃圾,结果造成混乱。

    除了关于未定义行为的语言规则之外,释放内存很可能会将内存返回操作系统。要么在调用free时直接调用,要么在操作系统本身内存不足并要求应用程序返回未使用的块时再调用


    当您意外地覆盖其他数据(如数组长度或函数的返回地址)时,悬空指针也会间接导致崩溃。撇开有关未定义行为的语言规则不谈,释放内存很可能会将该内存返回操作系统。要么在调用free时直接调用,要么在操作系统本身内存不足并要求应用程序返回未使用的块时再调用


    当您意外地覆盖其他数据(如数组长度或函数的返回地址)时,悬空指针也会间接导致崩溃。无法保证分配器不会将内存返回操作系统,也无法保证任何其他未定义行为

    据我所知,一个令人满意的答案应该包含一个代码示例,其中取消对悬空指针的引用会立即导致程序崩溃。下面是一个在Linux上(此时此地)崩溃的示例:

    #include <iostream>
    
    int main() {
        int* arr = new int[1000000];
        delete[] arr;
        std::cout << *arr << std::endl;
    }
    
    #包括
    int main(){
    int*arr=新int[1000000];
    删除[]arr;
    
    std::cout无法保证分配器d