C++删除动态数组只删除第一个元素
C++ Deleting dynamic array only deletes first element
我最近开始使用指针和动态数组,并学习如何理解它们。我正在关注C++初级读本(第5版),我相信这本书是2005年的,所以我有点不知道发生了什么,因为我觉得有些东西已经更新了。
我在这里和其他地方搜索了一下,这是故意的行为,还是我只是做错了什么。
int main()
{
double * p3 = new double [3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
cout << "p3 = " << p3[0] << ", " << p3[1] << ", " << p3[2] << endl;
p3 = p3 + 1;
cout << "Incrementing p3 = " << p3[0] << ", " << p3[1] << ", " << p3[2] << endl;
p3 = p3 - 1;
cout << "Decrementing p3 = " << p3[0] << ", " << p3[1] << ", " << p3[2] << endl;
delete [] p3;
cout << "After deleting p3 = " << p3[0] << ", " << p3[1] << ", " << p3[2];
return 0;
}
正在发生的事情是,在书中,它说;只要delete中的括号为空,它就应该删除整个动态数组,而在我的情况下,它只删除第一个元素(p3[0])。
我只是想知道它是否真的释放了内存,但因为我继续使用指针,它会产生一些奇怪的行为,或者这是应该发生的事情,而代码是错误的。
编辑:程序的输出
p3 = 0.2, 0.5, 0.8
Incrementing p3 = 0.5, 0.8, 1.37017e-309
Decrementing p3 = 0.2, 0.5, 0.8
After deleting p3 = 1.63786e-305, 0.5, 0.8
您甚至在删除任何内容之前就有未定义的行为。在调整CCD_ 1之后,访问CCD_。在释放内存块之后取消引用指针也是UB。不,你们不能只释放分配区块的第一个项目,只能释放整个区块。请注意,您还需要使用与用于分配的方法完全相反的free方法:new
-delete
、new []
-delete []
或(C样式)malloc
-free
。
您错过的是,像double
这样的标准值类型没有析构函数。你看,根本不需要触摸他们的内存来"清除"它,只要知道内存可以重复用于其他事情就足够了。
因此,当您在数组上调用p3 = p3 + 1;
0时,内存中的大部分数据都保持不变。但是,delete[]
决定立即重用数组中第一个double
占用的内存来存储其一些内部数据。这就是你在里面看到1.63786e-305
的原因。这不是存储的双精度,很可能是指向其他内部数据的指针。
在调用delete[]
之后触摸阵列的内存是未定义的行为。如果你这样做,任何事情都可能发生。所以,一定不要这样做。即使只是像你那样读取内存,也会立即破坏你的进程!
您可以断言您的delete[]
确实删除了所有数组元素,方法是在实际具有析构函数的元素数组上调用它:
#include <iostream>
class Foo {
public:
Foo() { std::cout << "constructing Foo at " << (intptr_t)this << std::endl; }
~Foo() { std::cout << "destructing Foo at " << (intptr_t)this << std::endl; }
};
int main() {
Foo* array = new Foo[3];
delete[] array;
return 0;
}
在我的机器上运行这个小测试程序,我得到以下输出:
在93925438098472处构建Foo
在93925 438098473处构建Foo
9392543809 8474处破坏Foo
939254389 8473处破坏Foo
正如您所看到的,所有三个对象都被构造,然后所有三个物体都以相反的顺序被销毁。一切都很好。
执行语句delete [] p3;
时,为数组分配的内存将被释放回操作系统,然后操作系统可以将该内存重新用于正在运行的任何进程。在PC上,内存通常仍会保留给同一个(您的)进程,因此访问它不会立即导致分段冲突(尽管这是未定义的行为)。然而,它可能被用于其他目的(例如,将其他信息存储在堆上的那个位置)。删除p3后,p3[0]引用的位置就是这样。
释放内存并不意味着它将被清除(所有字节重置为0)。这就是为什么在访问p3[1]和p3[2]时仍然可以看到旧值的原因。这只是意味着,内存不再受到任何保护,而不会被进程显式写入该地址。
您无法(据我所知)知道堆上的某个地址目前是否保留供您使用,这就是为什么建议在调用delete后立即将指针设置为NULL的原因。
delete [] p3;
p3 = NULL; // or for C++11: p3 = nullptr;
通过这种方式,您可以自己标记:当指针为NULL时,我已经释放了可能与它相关联的内存。
- 为什么它只打印双链接列表的第一个值,而我的程序却崩溃了
- std::find,返回所有找到的值的替代方法,而不仅仅是存在重复的向量的第一个值
- G++ 发出警告,要求删除一个代码的数组,但不删除另一个代码的数组
- 如何仅读取文本文件中的第一个值
- 在C++中,如何在第一个"system()"结束后执行第二个"system()"?
- 删除第 I 个元素
- 查找不在标准中的第一个值::设置<int>最小-最大值
- 避免在使用链接列表从 deque 中删除最后一个节点时出现内存泄漏
- std::字符串擦除以删除最后一个字母
- C++:忽略第一个 cin.ignore 之后的输入
- 在C++中打印多个矢量的第一个值
- C++去除前x个元素的有效方法,在不改变向量大小的情况下将第x+1个元素推到第一个
- C++第一个cout将不会打印
- 我们可以在第一个else-if条件结束后使用另一个else-if条件吗
- OpenGL:第二个VBO破坏了第一个VBO
- 为什么第一个Dynamic_cast没有投射到基类?
- 一个对象的两个指针.删除了一个指针,对象仍然存在
- OpenGL 2D游戏只绘制第二个精灵纹理而不是第一个
- 删除指针作为 std::map 的第一个键
- 删除二进制字符串中的第一个0