我有一个问题,为什么我可以访问某些内存,我认为这与我理解(或不理解)编译器如何在内存中保存内容的方式有关。这是我正在使用的示例代码:
标题文件:
#include <iostream>
using namespace std;
class A
{
public:
int value;
A (int newValue = 5)
{
value = newValue;
cout << "A()" << endl;
}
~A() { cout <<"~A()" << endl; }
void func1() {cout << "A::func1()" << endl; }
};
class B : public A
{
public:
B() { A::value = 0; cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
virtual void func1 () { cout << "B::func1()" << endl; }
};
class C : public B
{
public:
C() { cout << "C()" << endl; }
~C() { cout << "~C()" << endl; }
virtual void func1() { cout << "C::func1()" << endl; }
};
.cpp文件:
int main()
{
int i;
cout << endl;
A* pA = new A (5);
B* pB = new B;
C* pC = new C;
pA->func1();
pB->func1();
pC->func1();
delete pA;
delete pB;
delete pC;
cout << endl;
//here is my first question - why don't I get a compiler error here?
//why does the compiler know what this is? Didn't I delete it?
A* ppA = pC;
//here is my second question - why does this work?
//didn't I clear this memory?
ppA->func1();
B bObject;
B* ppB = &bObject;
ppB->func1();
cin >> i;
return 0;
}
我的问题就在评论中 - 为什么我没有在这些方面出错?
如果我更改.h文件,func1()
中的virtual
也是A
,我确实在该行上获得了访问冲突,但仍然没有编译时错误。
感谢您的任何解释:)
答案 0 :(得分:8)
编译器不会跟踪指针是否指向合法对象。这是一个复杂的分析,在大多数常见情况下都是不可能的。这就是为什么当你将删除的指针分配给另一个指针时它不会产生错误。
删除对象不会自动清除对象占用的内存。它将在未来的某个不确定点被覆盖,所以你永远不要依赖它。这称为未定义行为,未定义行为的标志之一是,即使不应该这样做,它似乎也可以工作。
答案 1 :(得分:7)
第一个问题的答案很简单:指令是在编译时编写的。编译器显然不知道该值是否已被删除,因此它只是盲目地将pC
的值复制到ppA
上。
你的第二个问题的答案是:它可能不起作用。你进入了可怕的未定义行为之地。想想爱丽丝梦游仙境,没有猫指导你。
基本上当你在指针上调用operator delete
时,你告诉操作系统它可以在需要时覆盖内存。 “如果需要的话。没有实际的内存擦除,只是承诺你将不再使用那块内存。
因此,当您尝试访问虚拟表以调用func1
时,数据可能仍然存在。或不。在这种情况下你会崩溃(如果你很幸运)。但你应该得到它,你违背了对操作系统的承诺,所以此时任何事情都会发生。
修改:请注意,func1
实际上从未使用this
,因此如果它不是虚拟的,您可以说((A*)0)->func1()
并且它可以正常工作。
答案 2 :(得分:1)
delete
不会从代码范围中删除名称。它是一个命令,用于将该内存标记为程序不再使用。该内存可以由下一次分配使用,或者在进程执行期间不再使用。
delete
不会为您排除内存。如果需要,你可以自己做。在它决定在那里放置新的分配之前,内存块中的内容不会改变。使用指向已删除内存的指针是一个非常糟糕的主意。
答案 3 :(得分:0)
内存释放功能,如删除,免费,HeapFree不会消灭内存。他们只是将它们标记为“未分配”,并且可以通过这些未分配的内存块完成进一步的请求。相同的内存块可用于服务多个内存分配调用,或只调用一个。
就像删除(Shift + Deleting)文件一样 - 文件实际上不会被标记为零,它只会被标记为“自由空间”。与文件分配一样,多个自由空间可用于一个文件(这就是我们拥有“碎片整理程序”的原因)。但是对于内存分配,多个空闲内存块无法完成对大内存块分配的服务。