我最近开始使用并学习理解指针和动态数组。我跟随2005年的C ++入门书(第5版),我相信,所以我对于发生的事情感到很遗憾,因为我觉得有些东西已经更新了。
如果这是预期的行为,或者我只是做错了什么,我已经在这里和其他地方进行了搜索。
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
答案 0 :(得分:2)
即使在删除任何内容之前,您还有未定义的行为。调整后<ContentPage.Content>
<local:CustomMap x:Name="customMap" MapType="Street"
WidthRequest="{x:Static local:App.ScreenWidth}"
HeightRequest="{x:Static local:App.ScreenHeight}" />
</ContentPage.Content>
访问p3 = p3 + 1;
将超出范围。释放内存块后取消引用指针也是UB。不,你不能只释放分配块的第一项,只有整个块。请注意,您还需要使用与用于分配的方法完全相反的免费方法:p3[2]
- new
,delete
- new []
或(C风格){{1} } - delete []
。
答案 1 :(得分:-1)
当执行语句delete [] p3;
时,为阵列分配的内存将被释放回操作系统,然后操作系统可以重新使用该内存以用于正在运行的任何进程。在PC上,通常仍会为同一个(您的)进程保留内存,因此访问它不会立即导致分段违规(尽管它是未定义的行为)。但是,它可能用于其他目的(例如,在堆上的该位置存储其他信息)。这是删除p3后p3 [0]所指的位置发生的情况。
释放内存并不意味着它将被清除(所有字节都重置为0)。这就是为什么在访问p3 [1]和p3 [2]时仍然可以看到旧值的原因。 它只是意味着内存不再受到过程中任何显式写入该地址的写入保护。
没有办法(我知道)让你知道堆上的某个地址目前是否保留供您使用,这就是为什么建议的做法是在调用后立即将指针设置为NULL删除它们。
delete [] p3;
p3 = NULL; // or for C++11: p3 = nullptr;
这样你就可以自己标记:当指针为NULL时,我释放了可能与之关联的内存。
答案 2 :(得分:-1)
您遗漏的是,像double
这样的标准值类型没有析构函数。你知道,根本没有必要触摸他们的记忆来“清除”它,只要知道记忆可以被重用于其他东西就足够了。
因此,当您在阵列上调用delete[]
时,内存中的大多数数据都保持不变。但是,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 在93925438098473建造Foo 在93925438098474建造Foo 破坏Foo,电话93925438098474
毁灭Foo at 93925438098473
在93925438098472破坏Foo。
如您所见,构建了所有三个对象,然后所有三个对象都以相反的顺序被破坏。一切都很好。