在c++开发中,会存在一个问题,在申请内存之后可能会忘记释放,导致内存泄漏,下面文章会从实现简单智能指针到安卓智能指针进行分析
1.内存泄漏举例
实例化对象指针忘记使用delete从而导致内存泄漏
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
};
void test_func(void)
{
Student* stu = new Student();
stu->print_info();
//此处忘记使用delete stu来销毁对象,导致内存泄漏
}
int main(void)
{
test_func();
}
结果:
Student()
just for test
2.改进方法1
在函数里面创建局部对象,在函数结束之后变量会自动销毁
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
};
void test_func(void)
{
Student stu;
stu.print_info();
}
int main(void)
{
test_func();
}
结果:
Student()
just for test
~Student()
对于局部变量来说,在函数结束之后,编译器会自动调用析构函数来销毁对象
3.改进方法2
局部变量和类指针结合解决未手动delete导致的内存泄漏
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
};
class sp
{
private:
Student* stu;
public:
sp():stu(NULL)
{
}
sp(Student* other)
{
cout << "sp()" << endl;
stu = other;
}
~sp()
{
cout << "~sp()" << endl;
if (stu)//如果stu存在,那么删除即可
{
delete stu;
}
}
//重载指针运算符,从而可以访问到Student中的print_info对象
Student* operator->()
{
return stu;
}
};
void test_func(void)
{
//以下会调用sp的构造函数sp(Student *other)
//Student *tmp = new Student()
//sp s(tmp)
sp s = new Student();
s->print_info();
}
int main(void)
{
test_func();
}
结果:
Student()
sp()
just for test
~sp()
~Student()
第二种写法:
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
public:
Student()
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
};
class sp
{
private:
Student* stu;
public:
sp():stu(NULL)
{
}
sp(Student* other)
{
cout << "sp()" << endl;
stu = other;
}
sp(sp &other)
{
cout << "sp(sp &other)" << endl;
stu = other.stu;
}
~sp()
{
cout << "~sp()" << endl;
if (stu)//如果stu存在,那么删除即可
{
delete stu;
}
}
//重载指针运算符,从而可以访问到Student中的print_info对象
Student* operator->()
{
return stu;
}
};
void test_func(sp &other)
{
sp s = other;
s->print_info();
}
int main(void)
{
int i = 0;
sp other = new Student();
for (i = 0; i < 2; i++)
test_func(other);
}
上面程序存在如下问题,当第一次调用test_func(other)时,other内部的stu指针和sp内部的指针指向同一个Student对象,当函数生命周期结束之后,会调用delete函数销毁Student对象,此时other对象已经不存在,那么下一次再调用test_func(other)函数之后会导致系统崩溃。所以需要考虑sp类内部的Student指针多次被调用的情况,解决方法是增加一个引用计数,当引用计数为0时才销毁sp类内部的stu指针
4.改进方法
使用引用计数保护对象不被过早的销毁
#include <iostream>
#include <string.h>
using namespace std;
class Student
{
private:
unsigned int count;
public:
Student():count(0)
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
void inc_strong(void)
{
count++;
}
void dec_strong(void)
{
count--;
}
unsigned int get_strong_count(void)
{
return count;
}
};
class sp
{
private:
Student* stu;
public:
sp():stu(NULL)
{
}
sp(Student* other)
{
cout << "sp()" << endl;
stu = other;
stu->inc_strong();//引用次数加1
}
sp(sp &other)
{
cout << "sp(sp &other)" << endl;
stu = other.stu;
stu->inc_strong();
}
~sp()
{
cout << "~sp()" << endl;
if (stu)
{
stu->dec_strong();
if ((stu->get_strong_count() == 0))//如果stu存在,那么删除即可
{
delete stu;
stu = NULL;
}
}
}
//重载指针运算符,从而可以访问到Student中的print_info对象
Student* operator->()
{
return stu;
}
};
void test_func(sp &other)
{
sp s = other;
s->print_info();
}
int main(void)
{
int i = 0;
sp other = new Student();
for (i = 0; i < 2; i++)
test_func(other);
}
优化:重载解引用操作符
Student& operator*()
{
return *stu;
}
改进五:将引用计数相关的操作抽离出来,并且将智能指针sp抽象为类模板
#include <iostream>
#include <string.h>
using namespace std;
class RefBase {
private:
unsigned int count;
public:
RefBase():count(0)
{
}
void inc_strong(void)
{
count++;
}
void dec_strong(void)
{
count--;
}
unsigned int get_strong_count(void)
{
return count;
}
};
class Student : public RefBase
{
public:
Student()
{
cout << "Student()" << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
void print_info(void)
{
cout << "just for test" << endl;
}
};
template<typename T>
class sp
{
private:
T* t;
public:
sp():t(NULL)
{
}
sp(T* other)
{
cout << "sp()" << endl;
t = other;
t->inc_strong();//引用次数加1
}
sp(sp &other)
{
cout << "sp(sp &other)" << endl;
t = other.t;
t->inc_strong();
}
~sp()
{
cout << "~sp()" << endl;
if (t)
{
t->dec_strong();
if ((t->get_strong_count() == 0))//如果stu存在,那么删除即可
{
delete t;
t = NULL;
}
}
}
//重载指针运算符,从而可以访问到Student中的print_info对象
T* operator->()
{
return t;
}
T& operator*()
{
return *t;
}
};
template<typename T>
void test_func(sp<T> &other)
{
sp s = other;
s->print_info();
}
int main(void)
{
int i = 0;
sp<Student> other = new Student();
for (i = 0; i < 2; i++)
test_func(other);
}