下面的代码是矩阵类的一部分析构函数的语句,在稀疏矩阵的析构中显式调用了对象m_matrix的析构函数,开始看似没问题,但是程序执行后总是有内存泄露发生。
//SparseMatrix中全局变量
ccs_matrix* m_matrix;
//析构函数
SparseMatrix::~SparseMatrix()
{
if (this->m_matrix!=NULL){
this->m_matrix->~ccs_matrix();//在这里主动调用了对象的析构函数
}
this->m_matrix = NULL;
}
//结构ccs_matrix
struct ccs_matrix
{
int m,n;
int* colptr;
//构造函数
……
//析构函数
~ccs_matrix()
{
delete[] colptr;
}
}
后来感觉m_matrix是指针,每次创建它都用到了new,应该最后delete掉。于是将this->m_matrix->~ccs_matrix();语句改为delete this->m_matrix;这样内存泄漏问题就解决了。
在网上查了下,感觉下面说的很有道理,应该是问题症结。
delete有两步操作
1.调用析构函数
2.调用operator delete释放内存
在c++里可以
显示调用析构函数
作用就是与
placement new相匹配
一般比如分配一段内存作为内存池
如下的
#include <iostream>
#include "tmp.h "
using namespace std;
class A {
public:
A( int i ) : _i( i ) { cout < < "constructor/n "; }
void print() { cout < < _i < < endl; }
~A() { cout < < "destructor/n "; }
private:
int _i;
};
char mem_pool[ 20 ];
int main()
{
A * pa = new ( & mem_pool[ 0 ] ) A( 25 );
pa-> print();
pa-> ~A();
return 0;
}
这种情况就不能用delete
1.调用析构函数
2.调用operator delete释放内存
在c++里可以
显示调用析构函数
作用就是与
placement new相匹配
一般比如分配一段内存作为内存池
如下的
#include <iostream>
#include "tmp.h "
using namespace std;
class A {
public:
A( int i ) : _i( i ) { cout < < "constructor/n "; }
void print() { cout < < _i < < endl; }
~A() { cout < < "destructor/n "; }
private:
int _i;
};
char mem_pool[ 20 ];
int main()
{
A * pa = new ( & mem_pool[ 0 ] ) A( 25 );
pa-> print();
pa-> ~A();
return 0;
}
这种情况就不能用delete
有人说:
Deconstructor is the same as other member functions, it won 't erase itself. 意思就是析构函数显式调用不会删除调用析构的对象自身,和上面一样,说明显式调用析构和delete的区别就是delete删除了对象自身
另外,显式调用析构函数有可能导致内存的两次释放,即调用时释放一次,自动析构时释放一次,导致程序错误。
顺便说明 构造函数和析构函数都可以显式调用,析构函数有时候必须显式调用。
前两天去hp面试,有个题问构造函数和析构函数可不可以显示调用。
回来上网查了下,原来两个都是可以显示调用的。如下:
class A
{
public:
A() { cout<<"a cnostructor"<<endl; }
~A() { cout<<" a destructor"<<endl; }
};
void main()
{
A a;
a.A::A();//显示调用构造函数,写成a.A()会报错。
a.~A();//显示调用析构函数,但是此时对象a并没有销毁。
}
此时的输出结果是:
a constructor
a constructor //显示调用构造函数的结果。
a destrucotr //显示调用析构函数的结果,此时对象并没有销毁。
a destructor //对象销毁时自动调用析构函数。
总结:显式调用构造函数和析构函数就想调用一般的函数一样,并不意味着创建或销毁对象。但是注意,如果构造函数中动态分配了空间,则显式调用构造函数会出现内存泄露;如果析构函数中释放动态分配的空间,则会出现多次释放同一内存,会出现严重错误。
回来上网查了下,原来两个都是可以显示调用的。如下:
class A
{
public:
A() { cout<<"a cnostructor"<<endl; }
~A() { cout<<" a destructor"<<endl; }
};
void main()
{
A a;
a.A::A();//显示调用构造函数,写成a.A()会报错。
a.~A();//显示调用析构函数,但是此时对象a并没有销毁。
}
此时的输出结果是:
a constructor
a constructor //显示调用构造函数的结果。
a destrucotr //显示调用析构函数的结果,此时对象并没有销毁。
a destructor //对象销毁时自动调用析构函数。
总结:显式调用构造函数和析构函数就想调用一般的函数一样,并不意味着创建或销毁对象。但是注意,如果构造函数中动态分配了空间,则显式调用构造函数会出现内存泄露;如果析构函数中释放动态分配的空间,则会出现多次释放同一内存,会出现严重错误。