所以我执行这段代码
#include <cstdlib>
#include <iostream>
int main()
{
char *test = new char[10];
strcpy(test, "Hello Ther");;
std::cout << test << std::endl;
delete[] test;
std::cout << test << std::endl;
return 0;
}
,输出
Hello Ther
Hello Ther
似乎delete[] test
语句没有做任何事情......根本没有运行时或编译时错误
完全难过我
答案 0 :(得分:8)
在您delete[]
数组后,没有更多数组。在此之后通过该指针的任何访问都有未定义的行为。
delete[]
应该调用数组元素上的析构函数并释放它使用的存储。由于char
没有析构函数,因此它只是释放存储空间。仅释放存储意味着它不再使用。
FWIW,您的代码中还有一个未定义行为的实例。 "Hello Ther"
有11个元素:末尾有一个null('\0'
)终止符。 strcpy
将其放入缓冲区中只有10个元素是未定义的行为。你需要一个带有11个元素空间的缓冲区:“Hello Ther”的10个字符加上空终止符。
这种错误,即缓冲区溢出,是安全漏洞的常见来源。至少从20世纪80年代开始,就出现了这种错误的着名漏洞。明智的做法是避免使用这种不安全的原语,而选择安全的现代原语(以及“现代”,我的意思是“从20世纪90年代开始”),如std::string
。因为,你知道,这是21世纪。
答案 1 :(得分:3)
您期望发生什么?
当您删除指针时,所有发生的事情都是在您调用new时提供给您的内存被返回给系统。如果在调用delete之后没有以任何方式分配或触摸内存(如在您的示例中那样),内存的旧内容仍可能存在。对于删除来说,删除所有内存都是零(一些编译器的调试版本会在删除时写入特殊值以使无效的内存访问更容易找到)。如果您确实通过分配更多内存或调用函数来触摸内存,那么该值可能会被破坏。虽然它可能没有,但这就是为什么在删除后访问指针被称为未定义的行为。
答案 2 :(得分:2)
在C ++中,无论是否分配,都可以访问内存。这会触发未定义的行为,但不会检查任何说明给定内存是否“可访问”。这是你的问题。这与基于VM的语言形成对比,后者会为您检查内存访问。
避免这种错误的一个常见习惯是这样做:
delete[] myArray;
myArray = NULL; // preferably "nullptr" in C++11
CPU拒绝任何对NULL
地址的访问。它会向操作系统发出错误警告(这可能会以段错误或等效错误结束您的程序)。
正如stonemetal所提到的,一些编译器/操作系统/分配器将检查调试版本中的内存访问,但不会在释放模式下进行速度增益。
注意:如果您尝试随机访问未分配的内存,则会遇到页面错误,但这有点偏离主题。