为什么要使用智能指针?
为了防止程序员遗忘释放指针,使用智能指针可以帮助我们管理内存,防止内存泄漏
智能指针的原理?
一、从较浅的层面看,智能指针是对普通的指针进行了封装,这使得智能指针实质其实是一个对象,只是表现的却像一个指针。
二、由于智能指针是一个类对象,在被调函数执行完,对象将会被删除。同时,它指向的内存也会被删除的因此实现了指针的释放。
三、智能指针重载了->符和=符,重载这两个符号时不能带参数
智能指针的作用?
1.智能指针的作用是防止忘记delete释放内存,以及程序处理异常时进入catch块忘记释放内存。
2.智能指针还有一个作用就是截获临时变量并且保存下来。
例:
Animal A = new Animal();
Animal B = A;(拷贝构造会生成一个临时变量)
虽然只生成了两个对象,但是却借助了一个临时变量
通过智能指针,我们可以把这个临时对象截获,并且赋给 B; 节省了一次拷贝过程
头文件 : memory.h
三种智能指针:
shared_ptr, weak_ptr, unique_ptr
auto_ptr (老版auto_ptr,已经弃用,不多讨论)
建议 1 : 每种指针都有不同的使用范围,unique_ptr指针优于其它两种类型,除非对象需要共享时用shared_ptr。
建议 2 : 如果你没有打算在多个线程之间来共享资源的话,那么就请使用unique_ptr。
建议 3 : 使用make_shared而不是裸指针来初始化共享指针。
建议 4 : 在设计类的时候,当不需要资源的所有权,而且你不想指定这个对象的生命周期时,可以考虑使用weak_ptr代替shared_ptr。
auto_ptr例:我们用auto_ptr指向一个类:auto_ptr<类名>pt(new 类名(参数));
当使用智能指针赋值时,如:pt1=pt2, 此时pt1会直接接管pt2。而pt2被释放置空。(此处也证实了智能指针就是一个类的对象)
unique_ptr :
( unique:独一无二的,唯一的)
unique_ptr 是C11用来取代auto_ptr的产物,它具有auto_ptr的所有特性,并且实现了移动语义。
unique_ptr 从名字就可以看出它是一个独享所有权的智能指针,它提供了严格意义上的所有权。
包括:
1、拥有且独享它指向的对象
2、无法进行复制构造,无法进行复制赋值操作。即:无法使两个unique_ptr指向同一个对象。但是可以进行移动构造和移动赋值操作
3、保存指向某个对象的指针:当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象。
unique_ptr 可以实现如下功能:
1、为动态申请的内存提供异常安全
2、将动态申请的内存所有权传递给其他函数
3、从某个函数返回动态申请内存的所有权
4、在容器中保存指针
unique_ptr test_pt(nullptr); //声明一个空的unique_ptr指针
判断智能指针是否为空:
if(ptest.get() == nullptr);
reset()方法:
可以使指针重新指向一个新的对象。
release()方法:
可以把智能指针赋值为空,但是它原来指向的内存空间没有被释放,相当于它只是释放了指针对资源的控制权。
get () 方法:
返回一个初始的指针。
move () 方法:
移动函数。
swap()方法:
swap(pt1,pt2) or pt1.swap(pt2)
可以用来交换智能指针。
下面的例子:改自:
https://www.cnblogs.com/wuyepeng/p/9741241.html**
class Test2
{
string str;
public:
Test2(string s)
{
str = s;
cout<<“the test2 creat\n”;
}
~Test2()
{
cout<<“the test2 delete:”<<str<<endl;
}
string & getStr() //我们一般使用引用来写get方法
{
return str;
}
void setStr(string s)
{
str = s;
}
void print()
{
cout<<str<<endl;
}
};
//创建一个函数,返回值是Test2类的unique_ptr指针
unique_ptr fun()
{
return unique_ptr(new Test2(“789”));//调用了构造函数,输出Test creat
}
int main()
{
unique_ptr test_pt(nullptr);//声明一个空的unique_ptr指针
unique_ptr test_pt1(new Test2(“123”));//调用构造函数,输出Test creat
unique_ptr test_pt2(new Test2(“456”));//调用构造函数,输出Test creat
test_pt1->print();//输出123
test_pt2->print();//输出456
cout<<&test_pt1<<endl;
cout<<&test_pt2<<endl;
//不能直接test_pt2 = test_pt1。调用move()后test_pt2原本的对象会被释放,test_pt2对象指向原本test_pt1对象的内存,输出Test delete 456
//但是此时测试 test_pt1 ,使用test_pt1调用原成员会导致程序终止。分析:test_pt1 对象应该是被释放了,因该是有未处理的异常所导致
//先了解一下move()的实现机制?
test_pt2 = move(test_pt1);
test_pt2->print();
//test_pt1->print();
//cout<<&test_pt1<<endl;
cout<<&test_pt2<<endl;
if(test_pt1 == nullptr)
cout<<“ltest_pt1 = nullptr\n”;//因为两个unique_ptr不能指向同一内存地址,所以经过前面move后test_pt1会被赋值nullptr,输出test_pt1=nullptr。证实了我们上面的猜想。
Test2 * p = test_pt2.release();
//release成员函数把test_pt2指针赋为空,但是并没有释放指针指向的内存,所以此时p指针指向原本test_pt2指向的内存
p->print(); //输出123
test_pt1.reset§; //重新绑定对象,原来的对象会被释放掉,但是test_pt1对象本来就释放过了,所以这里就不会再调用析构函数了
test_pt1->print(); //输出123
test_pt2 = fun(); //这里可以用=,因为使用了移动构造函数,函数返回一个unique_ptr会自动调用移动构造函数
test_pt2->print(); //输出789
return 0; //此时程序中还有两个对象,还需调用两次析构函数
}
share_ptr :
( share:分享、共享)
Share_ptr : 从名字我们就可以知道,这是一个可以实现共享的指针。即: 多个share_ptr 指针可以指向同一个资源,而不会出现指针悬挂现象。
Share_ptr 的 用法 和 unique_ptr 类似