Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 您如何知道如何取消分配指针数组?_C++ - Fatal编程技术网

C++ 您如何知道如何取消分配指针数组?

C++ 您如何知道如何取消分配指针数组?,c++,C++,如果我有这样一个指针数组: char* p[3]; p[0] = new char; p[1] = new char[10]; p[2] = &c; 假设我不能使用std::string,我怎么知道如何在没有看到定义的情况下取消分配它?我如何知道在遍历数组时使用delete或delete[],或者它是否指向堆栈变量或堆上?编译器不会将此信息保存在任何位置。您必须自己保存它。如果您知道您有一个由new[]创建的数组,您只需使用delete[]将其删除即可;这是你必须履行的合同 如果您不

如果我有这样一个指针数组:

char* p[3];

p[0] = new char;
p[1] = new char[10];
p[2] = &c;

假设我不能使用
std::string
,我怎么知道如何在没有看到定义的情况下取消分配它?我如何知道在遍历数组时使用
delete
delete[]
,或者它是否指向堆栈变量或堆上?

编译器不会将此信息保存在任何位置。您必须自己保存它。

如果您知道您有一个由
new[]
创建的数组,您只需使用
delete[]
将其删除即可;这是你必须履行的合同


如果您不知道某些内容是否由您分配,那么您就存在我们称之为内存泄漏的问题,因为您将无法释放它,除非您想冒程序崩溃的风险。

我正在考虑这个问题,这是一个非常好的问题,但我认为,您就是做不到


由于我更习惯于编写C语言,我认为这是不可能的,因为这些信息必须存储在某个地方(至少在C语言中),据我所知,情况并非如此。

简短回答:你不知道,除非你知道它是如何通过编写代码的方式分配的

详细回答:没有(通用的、可移植的方法)来确定如何或是否使用
newchar
将某个元素分配为单个元素,或使用
newchar[10]将其分配为数组或根本没有分配。理论上,如果知道堆的位置,可以检查某个地址是否在“堆内”,但如果不了解特定系统的内存布局,就无法简单地知道什么是堆、什么是堆栈以及什么是全局数据,在不同的操作系统上编译相同的代码,甚至在同一操作系统的不同处理器架构上编译相同的代码,所有这些都会发生变化。要找出它是单个还是数组分配更难,如果大多数可能的话,大多数C++运行时甚至不会检测到这个,在你做代码> Car *P=新char [10 ];删除p;< /C> >它会崩溃/错误行为或者“不管怎样,因为它没关系”。根据您的运气,C++运行库设计和机器体系结构——参见下面的进一步讨论。
因此,您必须将其作为代码的一部分进行跟踪(或者根本不编写这样的代码,这是我的偏好),或者使用其他构造(智能指针可以工作,向量可以工作)

进一步:如果您有一种方法来确定某个内容是否来自堆,那么您仍然无法确定它是“原始分配还是其他内容”。想象一下:

char *p[2];

p[0] = new char[10];
p[1] = p[0] + 3;
现在,
p[1]
指向堆内,但不是堆本身的分配,而是堆内由
p[0]
进行分配的位置。因此,基本上,这几乎是不可能做到的,即使我们知道堆、数据和堆栈内存的位置——这是我们一般无法知道的

作为旁注,人们经常说“heap”,好像它是一个连续的内存块。这在大多数现代操作系统中并不常见,因为有许多不同的方式可以占用特定的内存。它可以作为初始加载可执行文件时加载的代码、数据或堆栈的一部分进行分配。但它也可以是共享库(.so或.dll等)[具有代码和数据空间]的一部分,它们通常被指定一个特定地址,以避免为每个用户“重新定位”共享库,并且一段内存可以是内存映射文件或共享内存分配-至少有时,可以在内存中指定一个特定的地址,因此在“堆”内存区域的中间有一个地址。因此,当我们说“堆”时,我们真正的意思是“操作系统认为我们可以用来存储东西的任何可用内存地址”,而不是从A到B的一条没有孔的直线地址。它更像是A-B、F-J、M、P和T-V,它们是“堆”


正如Marcus在评论中提到的,有些操作系统故意“移动对象”(地址空间随机化),以使有非法目的的人更难依靠从一个内存区域到另一个内存区域的距离来滥用堆栈覆盖来“破解”系统。

你不会,所以你会将它们包装在合适的对象中,为你管理它。你不会,这就是为什么写这样的代码是一个可怕的想法。你不会。指针只存储地址而不存储其他信息,这就是为什么您永远不应该尝试单独使用它们来管理分配的内存。总是用其他类型(如
std::string
,如果你没有不使用它的神秘原因)来包装它们,它们知道应该如何管理它们。而且
delete p[2]
可能会非常有趣(未定义的行为),因为我猜
c
是一个堆栈/静态变量,如果你不能使用
std::string
,那么明智的做法是立即实现你自己的string类。“没有(通用的、可移植的方式)”甚至还有地址空间随机化,这完全是不可能的。