智能指针:动态内存管理是由一对运算符完成的:new和delete。默认情况下,动态分配的对象是默认未初始化的,这意味着内置类型和组合类型的值将是未定义的,而类类型对象将用默认构造函数进行初始化。
string *ps = new string; //定义一个指向字符串的指针,初始化为空
int* pi = new int; //pi指向一个未初始化的int
动态内存管理会出现两种问题:
1、忘记释放内存,会造成内存泄漏;
2、在有指针引用的情况下就释放了它,就会产生引用非法内存的指针。
所以,为了更加安全的使用动态内存,引入了智能指针的概念。智能指针是一个类,重载了->和*操作符。由类来实现对动态内存的管理,所有的智能指针都有一个explicit构造函数。
explicit关键字:使用该关键字修改的构造函数,将不能使用隐式转换,只能通过强制类型转换
auto_ptr:auto_ptr在进行拷贝构造时,内部会发生资源访问元的移交,所以在拷贝构造或者赋值时,原智能指针将不能再次去访问资源。
class Test
{
public:
Test(string s)
{
str = s;
cout << "Test create" <<endl;
}
~Test()
{
cout << "test delete " << endl;
}
void print()
{
cout << "str = " << str << endl;
}
}
int main()
{
auto_ptr<Test> p(new Test("abc")); //调用构造函数
auto_ptr<Test> p2(new Test("ghh")); //调用构造函数
p2 = p; //将p的地址拷贝给p2,此时释放p,调用p的析构函数
p2->print();
}
unique_ptr:在auto_ptr基础上禁用拷贝构造和赋值运算符重载函数;
unique_ptr& operator=(const unique_ptr&) = delete;
unique_ptr(const unique_ptr&) = delete;
使用unique_ptr无法使用拷贝构造函数,无法进行复制操作,应该使用std::move函数。unique_ptr指向的堆内存无法同其他unique_ptr共享,即每个unique_ptr独自拥有最其所指堆内存的空间的所有权。
int main()
{
unique_ptr<Test> p = new Test("asdd"); //错误使用,不能使用复制操作
unique_ptr<Test> p(new Test("asdd")); //调用构造函数
unique_ptr<Test> p2(new Test("ghjjj")); //调用构造函数
p2 = move(p); //调用了move后p2原本的对象会被释放,指向p的对象
}
shared_ptr:shared_ptr是基于“引用计数”的实现,多个shared_ptr指向同一块动态堆内存,并维护一个共享的引用计数器,记录了引用同一个对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象。
int main()
{
//空的shared_ptr指针,他的引用计数是0
shared_ptr<int> p1; //不传入任何实参
shared_ptr<int> p2(nullptr); //传入空指针nullptr
//用具体值初始化智能指针对象指向的内存
shared_ptr<int> p1(new int(1111));
cout << *p1 << endl;
//用另一个智能指针对象初始化当前指针对象
shared_ptr<int> p2 = p1;
//shared_ptr<int> p4 = make_shared<int>(2);
//通过成员函数use_count()来查看资源的所有者个数
cout<<p2.use_count()<<endl;
p1.reset(); //重新绑定对象,当还有指针指向对象绑定该地址时,就不会释放该对象的内存空间
p2.reset(); //当p2是最后一个绑定该对象的指针时,释放该内存,调用析构函数
}
weak_ptr:要搭配 shared_ptr 一起使用,weak_ptr不会增加资源的引用计数,weak_ptr 不能直接用来访问资源。需要用 lock 方法转换为shared_ptr ;
int main()
{
shared_ptr<int> sp1,sp2;
weak_ptr<int> wp;
sp1 = make_shared_ptr<int>(20); //初始化shared_ptr
wp = sp1; //sp1 ,wp 指向同一对象
sp2 = wp.lock(); //sp2指向
sp1.reset(); //释放sp1
sp1 = wp.lock(); //将sp1加入
return 0;
}