前言:智能指针部分的知识实在是太多了,好多东西我也不是很理解,限于篇幅和我个人能力,我这篇文章只能总结部分有关问题,更多知识点还需要去看c++ primer这本书的相关内容,另外auto_ptr由于已经过时,本文也不会提及。
在c++中动态内存的管理是用一对运算符完成的:new和delete
new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针。
delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
在c语言中,程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们。
而这样的话使用普通指针动态内存管理,就会有好多缺点
1.容易忘记释放,会造成内存泄漏;
2.已经在一个地方释放,又在另一个地方重新释放;
3.使用已经释放的内存,就会产生引用非法内存的指针。
4.调用者要自己通过delete释放内存;
在c++中的用普通指针管理动态内存的注意事项
int *pi1 = new int;//如果分配失败,new跑出std::bad::alloc
int *pi2 = new(nothrow) int; //如果new分配失败,new返回一个空指针
Foo obj;
auto p1 = new auto(obj); //p指向一个与obj类型相同的对象,该对象用obj进行初始化
/* auto p2 = new auto(1,2,3);//错误,括号中只能有单个初始化器 */
上段代码中Foo的源码
//一个函数,返回一个shared_ptr,指向一个foo类型的动态分配的对象
//对象是通过一个类型为T的参数初始化的
class Foo
{
public:
const int test;
//const成员必须使用列表初始化
Foo():test(0){
};
//如果不是const,定义了自己使用的构造函数,想继续使用默认的构造函数,加下面的代码
/* Foo() = default; */
Foo(int i):test(i){
}
};
因此在c++中,为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。
智能指针的优点
就算程序块提前结束,智能指针也内存在不需要时进行释放。
智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。标准库提供的两种智能指针的区别在于管理底层指针的方法不同。
- shared_ptr允许多个指针指向同一个对象。
- unique_ptr则“独占”所指向的对象。
- 标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。
那么之后我就来为大家介绍一下智能指针。
(一)shared_ptr
简单介绍
shaped_ptr有一个关联的计数器,每当拷贝一个智能指针的时候,计数器就会增加1,如果我们给一个shared_ptr赋予一个新值的时候,就把的计数器数值减1,或者 一个shared_ptr 离开了原先的作用域,也就是该shared_ptr被销毁的时候,计数器也会减1。
基本操作 | 意义 |
---|---|
shared_ptr p | 空智能指针,可以指向类型为 T 的对象 |
p | 将 p 用作一个条件判断,若p指向一个对象,则为true |
*p | 解引用p,获得它指向的对象 |
swap(p,q) | 交换 p 和 q 中的指针 |
p.unique() | 若p.use_count() 为1,返回true,否则返回 false |
p.use_count() | 返回与p共享的智能指针的数量 |
p.get() | 返回 p 总保存的指针 |
这里附上一段代码是在函数中关于引用计数的问题,这里就和c指针很像了。
template <typename T>
shared_ptr <Foo> factory(T argg){
//恰当的处理
//share_ptr负责释放内存
return make_shared<Foo>(argg);
}
template <typename T>
shared_ptr <Foo> use_factory(T argg){
shared_ptr<Foo> p = factory(argg);
//使用p
return p; //返回p,引用计数+1,对于代码来说,这个像是
//p离开了作用域,但是由于引用计数+1,所以不会释放内存,有点像指针
}
template <typename T>
void use_factory(T argg){
shared_ptr<Foo> p = factory(argg);
//使用p
//离开作用域,整个就结束了
}
定义一个shared_ptr
shared_ptr<int> p5 = make_shared<int>();
//p5是一个指向值初始化的int,初始值0
/* vector<string>(2); */
auto r = make_shared<int>(42);
r = p5;
shaped_ptr的特性
(图源网络,侵删,其实就是c++ primer上面的内容)
关于shaped_ptr的内存分配
可以使用make_shared函数进行内存分配,是最安全的分配方法,和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
//最安全的分配和动态使用内存的方法
shared_ptr<int> p3 = make_shared<int>(42);
//指向了一个42int的shape——ptr
shared_ptr<string> p4 = make_shared<string>(10,'9');
//指向了一个“99999999”的string
shared_ptr<int> p5 = make_shared<int>();
//p5是一个指向值初始化的int,初始值0
当然,shared_ptr也可以和和new的结合使用
//由于智能指针的构造函数是explicit的
//所以只能使用直接初始化
/* shared_ptr<int>p1 = new int(1024);//错的 */
shared_ptr<int> p2(new int(42));
/*--------------------------------------------------*/
//shared_ptr的拷贝
/* shared_ptr<int> clone(int p){ */
/* retur