智能指针 auto_ptr、 shared_ptr 、weak_ptr的使用方法及注意事项
#include<iostream>
#include<memory>
using namespace std;
///////////////////////////////auto_ptr/////////////////////////////////////////////////////////////
//boost中 scoped_ptr和auto_ptr一样 禁止用户进行拷贝和赋值头文件#include<boost/scoped_ptr.hpp>
class A
{
public:
A(int a ):_a(a)
{
cout << "A的构造函数" << endl;
}
~A()
{
cout << "A的析构函数" << endl;
}
int _a;
};
int main(void)
{
//c++ 98的auto_ptr
auto_ptr<A>p1(new A(100));
auto_ptr<A>p1(new A[100]);//报错 不能接受数组指针可以使用scoped_arry
cout << p1->_a << endl;
auto_ptr<A>p2(p1);//调用拷贝构造或赋值函数函数,此时P1失去所有权
auto_ptr<A>p2;
p2 = p1;
p1->_a;//报错 p1在拷贝或赋值给p2时失去了所有权
p2->_a;//正确
return 0;
}
///////////////////////////////shared_ptr 共享所有权的智能指针及shared_ptr使用的四个陷阱/////////////////////////////////////////////////////////////
//shared_ptr使用引用计数加,每个shared_ptr的拷贝都指向相同的内存,每关联拷贝一次 内部引用计数加1
class A
{
public:
A(int a) :_a(a)
{
cout << "A的构造函数" << endl;
}
~A()
{
cout << "A的析构函数" << endl;
}
int _a;
};
////配合陷阱3循环引用导致的内存泄漏
class B1;
class A1
{
public:
A1()
{
cout << "A1构造函数!" << endl;
}
~A1()
{
cout << "A1析构函数!" << endl;
}
shared_ptr<B1>m_pb;
};
class B1
{
public:
B1()
{
cout << "B1构造函数!" << endl;
}
~B1()
{
cout << "B1析构函数!" << endl;
}
shared_ptr<A1>m_pA;
};
int main(void)
{
//c++11的shared_ptr
shared_ptr<A>p1(new A(100)); //初始引用计数为1
cout << "是否是唯一拥有者:" << p1.unique()<<" " <<"拥有者数量:"<<p1.use_count()<< endl;
shared_ptr<A>p2(p1);//拷贝引用计数+1为2
cout << "是否是唯一拥有者:" << p1.unique() << " " << "拥有者数量:" << p1.use_count() << endl;
shared_ptr<A>p3;
p3 = p2; //赋值拷贝引用计数+1
cout << "是否是唯一拥有者:" << p1.unique() << " " << "拥有者数量:" << p1.use_count() << endl;
cout << "内存:" << p1.get() << " " << p2.get() << " " << p3.get() << endl;
//全部释放所有权
p1.reset(); //引用计数 - 1
p2.reset(); //引用计数 - 1
p3.reset(); //引用计数 - 1 这里调用结束A对象析构
/////////////////////////shared_ptr使用陷阱////////////////////////////////
//陷阱1.不能使用智能指针指向栈内存地址 所有智能指针皆存在这个陷阱
int ma = 10;
shared_ptr<int>p4(&ma);//这里不会出错 但是return后会报错 栈内存释放后 智能指针在释放 释放了两次
cout << "p4拥有者数量: " << p4.use_count() << endl;
//陷阱2.不能多次引用同一原指针,否则同一内存会被delete多次
int *pInt = new int(10);
//两个对象管理同一个内存
shared_ptr<int>p5(pInt);
//正确的写法 shared_ptr<int>p6(p5);
shared_ptr<int>p6(pInt); //错误的写法
//这里输出为1 p2是直接引用原指针 p2无法感知p1
cout << "p6拥有者数量:"<<p6.use_count()<<endl;
//陷阱3.循环引用导致的内存泄漏
shared_ptr<A1>pa(new A1()); //此刻Pa指向的内存引用计数+1
shared_ptr<B1>pb(new B1()); //此刻Pb指向的内存引用计数+1
//引用计数+1 都变成了2 在return之后由于m_pa和m_pb是在类中定义的不会自动释放导致引用计数只释放了一次
//导致两个类析构函数不会执行
pa->m_pb = pb;//此刻m_pb及m_pb指向的内存引用计数+1=2
pb->m_pA = pa;//此刻m_pA及pa指向的内存引用计数+1=2
//陷阱4.shared_ptr管理的内存只能是new出来的不能是malloc出来的
return 0;
}
////////////////////////////////make_shared/////////////////////////////////////
/*
make_shared的作用:
1、shared_ptr消除了显示的delete调用,很大程度上避免了程序员忘记delete而导致的内存泄漏,
但shared_ptr的构仍按需要new 导致了调用的不对称性,所以用make_shared来构造对象,隐藏new的细节
2、std::make_shared(比起直接使用new)的一个特性是能提升效率。使用std::make_shared允许编译器
产生更小,更快的代码,产生的代码使用更简洁的数据结构。每个std::shared_ptr都指向一个控制块,
控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。
因此直接使用new,需要一块内存分配给Widget,还要一块内存分配给控制块。如果使用std::make_shared来替换
一次分配就足够了。这是因为std::make_shared申请一个单独的内存块来同时存放Widget对象和控制块。这个优化
减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次
*/
class A2
{
public:
A2(int a, double b):_a(a), _b(b)
{
cout << "A1构造函数!" << endl;
}
~A2()
{
cout << "A1析构函数!" << endl;
}
int _a;
double _b;
};
int main(void)
{
int a = 5;
double b = 1.0;
//new的方式
//shared_ptr<A2>p1(new A2(a,b));
//make_shared的方式
shared_ptr<A2>p2 = make_shared<A2>(a,b);
shared_ptr<A2>p3 = p2;
cout << "拥有者数量:" << p3.use_count()<<endl;
return 0;
}
////////////////////////////////weak_ptr弱引用/////////////////////////////////////
/*
作用:协助shaed_ptr工作 他只可以通过一个shared_ptr或者另一个weak_ptr对象进行构造
他的构造不会引起引用计数的增加或减少,用来监测shared_ptr的拥有者数量 相当于只读不能写
注:weak_ptr监管的是shared_ptr指向的内存,和由谁构造的没关系。
方法: expired 检测所管理的对象是否释放 lock创建新的对shared_ptr并使计数+1
reset 将weak_ptr置空 swap交换两个 weak_ptr
运用场景: 解决管理内存是否被释放
解决循环引用问题
在使用weak_ptr是,我们一般会先用expired()判断其是否过期,如果没有过期则可访问所管理的资源
但weak_ptr并不能直接操作资源,想要操作资源的话需要使用lock()函数返回一个shared_ptr来操作资源
*/
class A3
{
public:
A3(int a, double b):_a(a), _b(b)
{
cout << "A1构造函数!" << endl;
}
~A3()
{
cout << "A1析构函数!" << endl;
}
int _a;
double _b;
};
int main(void)
{
int a = 5;
double b = 1.0;
shared_ptr<A3>p2 = make_shared<A3>(a,b);
shared_ptr<A3>p3 = make_shared<A3>(a, b);
weak_ptr<A3>p4(p2); //引用计数不变
cout << "拥有者数量:" << p4.use_count()<<endl;
//p2.reset()引用计数减1 p2无效 但是对由其构造出来的p4没有影响
p2.reset();
cout << p4.expired() << endl;
shared_ptr<A3>p5 = p4.lock();//lock()返回创建的shared_ptr指针 引用计数+1
cout << "拥有者数量:" << p5.use_count() << endl;
cout << "监管的对象是否被释放杆:" << p5._Expired() << endl;
//释放weak_ptr 但不影响监管的share_ptr对象
p5.reset();
return 0;
}
//////////////////weak_ptr解决循环引用的问题/////////////////////////////////////////
class A
{
public:
A()
{
cout << "A1构造函数!" << endl;
}
~A()
{
cout << "A1析构函数!" << endl;
}
//shared_ptr<A>m_pa;
//解决方案 循环引用的时候不会增啊引用计数
weak_ptr<A>m_pa;
};
int main(void)
{
shared_ptr<A>Pa(new A());
//循环引用
Pa->m_pa = Pa;
return 0;
}