C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,其中 auto_ptr 是 C++98 提出的,C++11 已将其摒弃,并提出了 unique_ptr 替代 auto_ptr。虽然 auto_ptr 已被摒弃,但在实际项目中仍可使用,但建议使用更加安全的 unique_ptr,后文会详细叙述。shared_ptr 和 weak_ptr 则是 C+11 从准标准库 Boost 中引入的两种智能指针。此外,Boost 库还提出了 boost::scoped_ptr、boost::scoped_array、boost::intrusive_ptr 等智能指针,虽然尚未得到 C++ 标准采纳,但是在开发实践中可以使用。
在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
shared_ptr<指向的类型> 智能指针名;
注意:
1. 智能指针是explicit,不可以进行隐式类型转换。必须直接初始化形参。
2.裸指针可以初始化shared_ptr,但不推荐。智能指针和裸指针不要穿插使用。
shared_ptr<int> p(new int(100));
shared_ptr<int> q = new int(20); //编译报错,智能指针是explicit,不可以进行隐式类型转换。必须直接初始化形参
//裸指针可以初始化shared_ptr,但不推荐
int *p = new int;
shared_ptr<int> q(p);
标准库中的函数模板,安全,高效的分配和使用shared_ptr。
在动态内存中分配并初始化一个对象,然后返回指向此对象的shared_ptr。
shared_ptr<int> p = make_shared<int>(100);
shared_ptr<string> str = make_shared<string>(5, 'a'); //5个字符a生成的字符串
shared_ptr<int> q = make_shared<int>(); //q指向int,内存里面保存的值为0
q = make_shared<int>(250); //q先释放原内存,然后指向一个新int,内存里面保存的值为250
auto p2 = make_shared<int>(22); //用 auto类型推断
每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象
//如果参数为引用,则智能指针的引用计数不会增加
shared_ptr<int> Func(const shared_ptr<int> &p) {return p;}
int main(){
auto p = make_shared<int>(100);
auto q = Func(p);
return 0;
}
//如果参数为引用,则智能指针的引用计数不会增加
void Func(const shared_ptr<int> p) {return ;}
int main()
{
auto p = make_shared<int>(100);
p = make_shared<int>(5);
Func(p);
return 0;
}
shared_ptr<int> p(new int(100));
cout << p.use_count() << endl; //1
shared_ptr<int> p(new int(100));
cout << p.unique() << endl; //true;
shared_ptr<int> p(new int(100));
p.reset(new int(50));
struct A
{
int a = 100; //类内初始化
string name = "三种";
};
int main()
{
shared_ptr<A> p(new A);
cout << (*p).a << endl; //100
//shared_ptr p(new int(100));
//cout << *p << endl; //100
return 0;
}
shared_ptr<int> p(new int(100));
int* q = p.get();
*q = 45;
//delete q; //释放内存会导致程序崩溃
shared_ptr<string> p(new string("张飞"));
shared_ptr<string> q(new string("I Love China"));
p.swap(q);
cout << *p << endl;
shared_ptr<string> p(new string("张飞"));
p = nullptr;
shared_ptr<string> p(new string("张飞"));
if(p){cout << "" << endl;}
//自定义删除器
void Func(int *p)
{
//写一些日志
delete p;
}
int main()
{
shared_ptr<int> p(new int(12), Func);
shared_ptr<int> q(p);
q.reset(); //引用计数减1 ,q为nullptr;
p.reset(); //会调用自定义删除器
//删除器可以是一个lambda表达式
shared_ptr<int> m(new int(10), [](int* p) {delete p; });
return 0;
}
有些情况,默认删除器处理不了(用shared_ptr管理动态数组),需要我们自己指定删除器。
shared_ptr<int> p(new int[10], [](int *p){delete []p;});
shared_ptr<int[]> q(new int[10]); //此种写法不需要自定义删除器
class A
{
public:
A() {}
~A() {};
};
int main()
{
//shared_ptr p(new A[10]); //不自定定义删除器会报异常
shared_ptr<A> q(new A[10], [](A* q) {delete[]q; }); //需要写自己的删除器
//可以用default_delete来做删除器,default_delete是标准库里面的模板类
shared_ptr<A> p(new A[10], std::default_delete<A[]>());
//定义数组的时候在<>中加[]
shared_ptr<A[]> p(new A[10]);
return 0;
}
写个函数模板来封装shared_ptr数组
//写个函数模板来封装shared_ptr数组
template<typename T>
shared_ptr<T> Func(size_t size)
{
return shared_ptr<T>(new T[size], default_delete<T[]>());
}
int main()
{
shared_ptr<int> q = Func<int>(5);
return 0;
}
注意:两个shared_ptr指定了不同的删除器,只要他们所指向的对象类型相同,那么这两个shared_ptr也属于同一个类型
但凡一些高级的用法,使用时都有不少陷阱。
int *p5 = new int;
std::shared_ptr<int> p6(p5);
std::shared_ptr<int> p7(p5);// logic error
shared_ptr<int> p(new int(100));
int* q = p.get();
delete q; //不可以删除,会导致异常
function(shared_ptr<int>(new int), g());
//用到C++标准库里面的类模板:enable_shared_from_this;
//enable_shared_from_this中有一个弱指针weak_ptr,这个弱指针能够监视this,实际内部调用weak_ptr的lock()方法
class Test: public enable_shared_from_this<Test>
{
public:
shared_ptr<Test> Func() {
return shared_from_this();
}
};
int main()
{
shared_ptr<Test> p(new Test);
shared_ptr<Test> q = p->Func(); //返回this智能指针
//现在在外面创建Test对象的智能指针以及通过Test对象返回的this智能指针都是安全的
return 0;
}
weak_ptr使用可参考博客:C++智能指针【weak_ptr】基本使用
class B;
class A
{
public:
shared_ptr<B> b;
~A()
{
int a = 0;
}
};
class B
{
public:
shared_ptr<A> a;
~B()
{
int b = 0;
}
};
int main()
{
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
a->b = b;
b->a = a;
//两个析构函数都没有被执行,将A或B类里面的智能指针改成weak_ptr即可
return 0;
}