1、简要介绍
C++中共有4个智能指针,分别是auto_ptr、shared_ptr、weak_ptr、unique_ptr,其中auto_ptr在C++11中已弃用(由于某些原因可能导致程序崩溃)。智能指针是存储动态分配对象指针的类(相当于封装),用于生命周期的控制,当指针离开其作用域时,自动销毁动态分配的空间,防止内存泄漏。
2、auto_ptr(自动指针)
2.1 相关说明
(1)C++11中不推荐,unique_ptr对其进行了改进。本身是一个类模板(封装 / 托管),为指针提供了一个有限的垃圾收集工具,允许指针在auto-ptr对象本身被销毁时自动销毁它们指向的元素。
(2)auto-ptr对象具有获得分配给它们的指针的所有权的特性:对一个元素拥有所有权的auto-ptr对象负责销毁它所指向的元素,并在其自身被销毁时(栈上,离开作用域时)释放分配给它的内存。
(3)任何两个auto-ptr对象都不应该拥有同一个元素:当两个auto-ptr对象之间发生赋值操作时,所有权被转移,这意味着失去所有权的对象被设置为不再指向元素(它被设置为空指针)。
2.2 代码
#include<iostream>
#include<string>
#include<memory>
using namespace std;
class Person
{
public:
Person(string newName) : name(newName)
{
cout << "Construct person, name: " << name << endl;
}
~Person()
{
cout << "Destruct person, name: " << name << endl;
}
void showPerson()
{
cout << "Show person, name: " << name << endl;
}
string& getName()
{
return name;
}
private:
string name;
};
int main()
{
auto_ptr<Person> autoPson(new Person("瓜智"));
//get():返回智能指针指向的对象地址
autoPson->showPerson(); //运算符重载
autoPson.get()->showPerson();
cout << "Address1: " << &(*autoPson) << endl; //运算符重载
cout << "Address2: " << &(*(autoPson.get())) << endl;
cout << endl << "=======================================" << endl << endl;
//reset(): 释放指向的对象并设置新值
autoPson.reset(new Person("瓜牛"));
cout << endl << "=======================================" << endl << endl;
//release(): 释放指针
Person *ptrPson = autoPson.release();
//autoPson->showPerson(); //autoPson.get()->showPerson(); //内部对象指针已指向NULL,程序崩溃
ptrPson->showPerson();
delete ptrPson;
cout << endl << "=======================================" << endl << endl;
{
auto_ptr<Person> testPson(new Person("测试")); //栈
}
getchar();
return 0;
}
2.3 运行结果
3、unique_ptr(唯一指针)
3.1 相关说明
(1)和auto_ptr在使用上大致相同,unique_ptr不能在两个智能指针之间使用赋值操作,可以使用move函数进行操作。
3.2 代码
int main()
{
auto_ptr<Person> autoBo(new Person("小波"));
auto_ptr<Person> autoTao(new Person("小套"));
autoTao->showPerson();
autoTao = autoBo;
autoTao->showPerson();
//autoBo->showPerson(); //(赋值时)右值对象内部对象指针指向空,导致程序崩溃
cout << endl << "=======================================" << endl << endl;
unique_ptr<Person> uniqueSan(new Person("张三"));
unique_ptr<Person> uniqueSi(new Person("李四"));
//uniqueSi = uniqueSan; //不可访问赋值运算符(编译报错)
uniqueSi = std::move(uniqueSan);
uniqueSi->showPerson();
cout << endl << "=======================================" << endl << endl;
if(NULL == uniqueSan) //unique_ptr: 可以直接用智能指针与NULL进行比较
{
cout << "uniqueSan is NULL" << endl;
}
/*
if(NULL == autoBo) //auto_ptr: 没有匹配的"=="操作符(编译报错),需要取出内部指针对象(如下)
{
cout << "autoBo is NULL" << endl;
}
*/
if(NULL == autoBo.get())
{
cout << "autoBo is NULL" << endl;
}
getchar();
return 0;
}
3.3 运行结果
4、shared_ptr(共享指针)
4.1 相关说明
(1)共享指针采用引用计数,可与其他shared_ptr对象共享一个对象(指向同一个对象的地址,如下图代码中Person类的对象)。
(2)共享类型的shared_ptr对象具有获取指针所有权并共享该所有权的能力:一旦它们获得所有权,指针的所有者组将在最后一个所有者释放该所有权时负责对其删除。
(3)shared_ptr对象只能通过复制其值来共享所有权:如果两个shared_ptr是从同一个(非shared_ptr)指针构造(或生成)的,则它们都将拥有该指针而不共享它,当先释放其中一个对象(删除其托管对象),后释放另一个事,会导致潜在的访问问题。
4.2 代码
int main()
{
//shared_ptr::use_count: 在此指针上共享所有权的对象数(即:一个Person对象被几个智能指针对象托管/使用)
//shared_ptr::reset: 删除托管对象,获取新指针
//创建一个对象(小明),由一个智能指针对象(sharedMing)进行托管(访问操作)
shared_ptr<Person> sharedMing(new Person("小明"));
cout << sharedMing.use_count() << endl;//1
//此时,sharedMing和sharedMing1两个对象都指向小明
shared_ptr<Person> sharedMing1(sharedMing);
cout << sharedMing.use_count() << endl;//2
cout << sharedMing1.use_count() << endl;//2
//现在,sharedMing2也加入进来(指向小明)
shared_ptr<Person> sharedMing2(sharedMing1);
cout << sharedMing.use_count() << endl;//3
cout << sharedMing1.use_count() << endl;//3
cout << sharedMing2.use_count() << endl;//3
//现在呢,sharedMing3也加入进来(指向小明)
shared_ptr<Person> sharedMing3 = sharedMing;
cout << sharedMing.use_count() << " name: " << sharedMing->getName() << endl;//4 小明
cout << sharedMing1.use_count() << " name: " << sharedMing1->getName() << endl;//4 小明
cout << sharedMing2.use_count() << " name: " << sharedMing2->getName() << endl;//4 小明
cout << sharedMing3.use_count() << " name: " << sharedMing3->getName() << endl;//4 小明
cout << endl << "=======================================" << endl << endl;
//到这儿,sharedMing不要小明了,转而相中小琴(其他智能指针对象还没放弃小明,少了一个竞争对手,use_count减一)
sharedMing.reset(new Person("小琴"));
cout << sharedMing.use_count() << " name: " << sharedMing->getName() << endl;//1 小琴
cout << sharedMing1.use_count() << " name: " << sharedMing1->getName() << endl;//3 小明
cout << sharedMing2.use_count() << " name: " << sharedMing2->getName() << endl;//3 小明
cout << sharedMing3.use_count() << " name: " << sharedMing3->getName() << endl;//3 小明
cout << endl << "=======================================" << endl << endl;
//过了一段时间,sharedMing1和sharedMing2智能指针对象也弃小明而去了
sharedMing1.reset(new Person("小琴1"));//sharedMing2.use_count: 2
sharedMing2.reset(new Person("小琴2"));//sharedMing3.use_count: 1
cout << endl << "=======================================" << endl << endl;
//终于,sharedMing3也放弃了小明,小明没人要了,就卖了(销毁对象小明,无情)
sharedMing3.reset(new Person("小琴3"));
getchar();
return 0;
}
4.3 运行结果
5、weak_ptr(弱共享指针)
5.1 相关说明
(1)weak_ptr是用来解决shared_ptr自身存在的缺陷(两个类之间相互引用shared_ptr对象,导产生对象引用计数不能归0,导致内存泄漏)而设计的。
(2)weak_ptr也是一个模板类,但是不能直接定义weak_ptr对象,只能配合shared_ptr使用。可以将shared_ptr的对象赋给weak_ptr的对象,同时不会改变引用计数(use_count)。
5.2 代码
#include<iostream>
#include<string>
#include<memory>
using namespace std;
class Teacher;//类前置声明
class Person
{
public:
shared_ptr<Teacher> sharedTeacher;
weak_ptr<Teacher> sharedTeacher1;
string name;
Person(string newName) : name(newName)
{
cout << "Construct person, name: " << name << endl;
}
~Person()
{
cout << "Destruct person, name: " << name << endl;
}
void showPerson()
{
cout << "Show person, name: " << name << endl;
}
};
class Teacher
{
public:
shared_ptr<Person> sharedPerson;
shared_ptr<Person> sharedPerson1;
string course;
Teacher(string newCourse) : course(newCourse)
{
cout << "Construct teacher, course: " << course << endl;
}
~Teacher()
{
cout << "Destruct teacher, course: " << course << endl;
}
void showPerson()
{
cout << "Show teacher, course: " << course << endl;
}
};
int main()
{
//weak_ptr<Person> weakPerson(new Person("小燕"));//不能直接定义weak_ptr对象,编译不通过
//问题(方法体结束后,Person和Teacher的两个对象没有被销毁,导致内存泄漏)
{
shared_ptr<Person> sharedPerson(new Person("学霸"));
shared_ptr<Teacher> sharedTeacher(new Teacher("数学"));
cout << sharedPerson.use_count() << endl;//1
cout << sharedTeacher.use_count() << endl;//1
//交叉引用(赋值)
sharedPerson->sharedTeacher = sharedTeacher;
sharedTeacher->sharedPerson = sharedPerson;
cout << sharedPerson.use_count() << endl;//2
cout << sharedTeacher.use_count() << endl;//2
}
//问题(交叉引用后,两个智能指针对象计数都为2,方法体结束后,两个智能指针对象被释放,引用计数各减一,
//但还存在交叉引用的计数(计数不为0),导致内部托管的对象无法释放,内存泄漏)
cout << endl << "=======================================" << endl << endl;
//修改(将两个类中相互引用的智能指针对象,其中一个改为weak_ptr类型,因为weak_ptr不会增加计数)
{
shared_ptr<Person> sharedPerson1(new Person("学渣"));
shared_ptr<Teacher> sharedTeacher1(new Teacher("语文"));
cout << sharedPerson1.use_count() << endl;//1
cout << sharedTeacher1.use_count() << endl;//1
//交叉引用(赋值)
sharedPerson1->sharedTeacher1 = sharedTeacher1;
sharedTeacher1->sharedPerson1 = sharedPerson1;
cout << sharedPerson1.use_count() << endl;//2
cout << sharedTeacher1.use_count() << endl;//1 Person类中的sharedTeacher1对象未增加计数
}
//修改(当Teacher类的"语文"对象引用计数变为0后,释放整个"语文"对象,继而释放"语文"对象中的sharedPerson1)
getchar();
return 0;
}
5.3 运行结果