一、内存泄漏(臭名昭著的bug)
1.动态内存申请堆空间,用完后不规划还
2.c++语言没有垃圾回收的机制
3.指针无法控制所指向堆空间的生命周期
#include<iostream>
#include<string>
using namespace std;
class Test
{
private:
int i;
public:
Test(int i)
{
this->i = i;
}
int value()
{
return i;
}
};
int main()
{
for(int i=0; i<5; i++)
{
Test *p = new Test(i);//申请了空间后面又没有释放
cout<<p->value()<<endl;
}
return 0;
}
二、智能指针
1.指针生命周期结束时主动释放堆空间的内存
2.一片堆空间最多智能由一个指针标识(避免多次释放同一片内存)
3.杜绝指针运算和指针比较(防止访问越界等问题)
实现方法:
1.重载特征操作符(->和*)
2.只能通过类的成员函数重载
3.重载函数不能使用参数
4.只能定义一个重载函数
#include<iostream>
#include<string>
using namespace std;
class Test
{
private:
int i;
public:
Test(int i)
{
this->i = i;
cout<<"Test(int i)"<<endl;
}
int value()
{
return i;
}
~Test()
{
cout<<"~Test()"<<endl;
}
};
class poiter
{
private:
Test *mp;
public:
poiter(Test *p = NULL)
{
cout<<"poiter(Test *p = NULL)"<<endl;
mp = p;
}
poiter(const poiter& obj)
{
cout<<"poiter(const poiter& obj)"<<endl;
mp = obj.mp;
const_cast<poiter&>(obj).mp=NULL;
}
poiter& operator = (const poiter& obj)
{
cout<<"poiter operator = (const poiter& obj)"<<endl;
if(this != &obj)
{
delete mp;//这句在拷贝构造函数里是没有的,看输出结果即可知道原因
mp = obj.mp;
const_cast<poiter&>(obj).mp = NULL;//以上几条语句是权限转让,可以解决一片内存只有一个指针控制
}
return *this;
}
Test* operator -> ()
{
return mp;
}
Test& operator * ()
{
return *mp;
}
~poiter()
{
delete mp;//解决主动释放问题
}
};
int main()
{
poiter p1 = new Test(1);
poiter p2 = p1;//调用的是拷贝构造函数
cout<<p2->value()<<endl;
cout<<endl;
poiter p3;
poiter p4 = new Test(2);
p3 = p4;//调用的是赋值操作
cout<<p3->value()<<endl;
cout<<endl;
return 0;
}
打印结果:
Test(int i)
poiter(Test *p = NULL)
poiter(const poiter& obj)
1
poiter(Test *p = NULL)
Test(int i)
poiter(Test *p = NULL)
poiter operator = (const poiter& obj)
2
~Test()
~Test()
**
智能指针只能用来指向堆空间的对象或变量
**
小结:
1.指针特征操作符(->和*)可以被重载
2.重载指针特征操作符能够使用对象来代替指针
3.只能指针只能用于指向堆空间中的内存
4.只能指针的意义在于最大程度避免了内存问题