析构函数和内存释放,有一篇的总结,因为内容长,以后贴上来
先看个简易的
class A
{
public:
A(int i = 3){a = i;};
~A(){cout << "destructor" << endl;}
int value(){return a;}
private:
int a;
};
int main()
{
A a;
A *p = new(&a) A(10);
cout << a.value() << endl;
delete p;
return 0;
}
在a对象的地址上未析构a的时候,创建了新的无名堆对象,这样a的数据被覆盖了,
但是编译器并未收到析构函数调用的消息,所以它认为那块内存存放的仍然是a对象的数据,所以a.value()仍可以取回值,取回当时内存中那个地址处的值,这是已经是10了。
然后delete p的时候,执行两步工作,
1。无名对象的析构函数调用,告诉编译器,那块内存中的值不能解释成无名对象的数据了, 对于无名对象而言,已经无效了(但对于a对象而言,因为编译器并未收到a对象析构函数的调用,所以认为那块内存中的数据对于a而言仍是有效的,是a的数据的)
2。问题发生在这个时候,delete p的第二个动作,归还内存给系统,标识为 空闲内存(没有任何对象引用到的,没有任何函数占用的内存),而事实上,这是对于p所指对象而言,对于a对象,它仍引用到这块内存,这样产生了异常,系统认为是快空闲内存了,但确有个对象引用到了这块内存,行为属未定义。
这就好像两个指针指向同一块的内存,一个把内存释放了,另一个指针成了悬垂指针,对悬垂指针解引用取出的值无意义,随机的,看当时内存中的数据
简单的说,
构造函数就是通知编译器,这块内存的数据解释成一个对象,哪块是哪个数据成员的数据,这些信息是构造函数给编译器的,都是隐式给的;显式的动作 可以放在构造函数中(并未必需的)的,是初始化 (不给初始化值可以的,随机值),获取资源
析构函数就是通知编译器,这块内存中的数据以后无需维护了,可以让其它使用了,里面的数据再不能解释成类对象的数据了,析构函数调用之后可以两种选择
1。一般情况,归还内存,栈的,堆的,都是
2。保留内存,只析构对象,这常见于placement new,delete往往同时执行了两个动作,所以这是候并不能直接delete,而是显式调用析构函数(详细论述待以后的总结)
先看个简易的
class A
{
public:
A(int i = 3){a = i;};
~A(){cout << "destructor" << endl;}
int value(){return a;}
private:
int a;
};
int main()
{
A a;
A *p = new(&a) A(10);
cout << a.value() << endl;
delete p;
return 0;
}
在a对象的地址上未析构a的时候,创建了新的无名堆对象,这样a的数据被覆盖了,
但是编译器并未收到析构函数调用的消息,所以它认为那块内存存放的仍然是a对象的数据,所以a.value()仍可以取回值,取回当时内存中那个地址处的值,这是已经是10了。
然后delete p的时候,执行两步工作,
1。无名对象的析构函数调用,告诉编译器,那块内存中的值不能解释成无名对象的数据了, 对于无名对象而言,已经无效了(但对于a对象而言,因为编译器并未收到a对象析构函数的调用,所以认为那块内存中的数据对于a而言仍是有效的,是a的数据的)
2。问题发生在这个时候,delete p的第二个动作,归还内存给系统,标识为 空闲内存(没有任何对象引用到的,没有任何函数占用的内存),而事实上,这是对于p所指对象而言,对于a对象,它仍引用到这块内存,这样产生了异常,系统认为是快空闲内存了,但确有个对象引用到了这块内存,行为属未定义。
这就好像两个指针指向同一块的内存,一个把内存释放了,另一个指针成了悬垂指针,对悬垂指针解引用取出的值无意义,随机的,看当时内存中的数据
简单的说,
构造函数就是通知编译器,这块内存的数据解释成一个对象,哪块是哪个数据成员的数据,这些信息是构造函数给编译器的,都是隐式给的;显式的动作 可以放在构造函数中(并未必需的)的,是初始化 (不给初始化值可以的,随机值),获取资源
析构函数就是通知编译器,这块内存中的数据以后无需维护了,可以让其它使用了,里面的数据再不能解释成类对象的数据了,析构函数调用之后可以两种选择
1。一般情况,归还内存,栈的,堆的,都是
2。保留内存,只析构对象,这常见于placement new,delete往往同时执行了两个动作,所以这是候并不能直接delete,而是显式调用析构函数(详细论述待以后的总结)