不带引用的智能指针
/*
- 智能指针 保证能做到资源的自动释放
- 利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放
- 智能指针能不能定义到堆上
- CSmartPtr *p = new CSmartPtr(new int);
- 这是一个裸指针 也需要先delete掉
- */
解决浅拷贝问题
template <typename T>
class CSmartPtr{
public:
CSmartPtr(T *ptr = nullptr)
: mptr(ptr){
}
~CSmartPtr(){
delete mptr;
}
T &operator* (){
return *mptr;
}
T *operator->(){
return mptr;
}
private:
T *mptr;
};
int main(){
CSmartPtr<int> ptr1(new int);
CSmartPtr<int> ptr2(ptr1);
}
这种情况会出现浅拷贝,delete俩次。
防止浅拷贝方法1 重新定义拷贝构造函数
给当前对象重新开辟一块空间,用你的值来初始化我
CSmartPtr(const CSmartPtr<T> &src){
mptr = new T(*src.mptr);
}
~CSmartPtr(){
delete mptr;
mptr = nullptr;
}
但是这样会出现俩快资源,而用户就像管理一个资源
不带引用的智能指针
使用auto_ptr(不推荐)
auto_ptr<int> ptr1(new int);
auto_ptr<int> ptr2(ptr1);
*ptr2 = 20;
cout << *ptr1;
这样会报错,因为auto_ptr只会管理最后一个资源,前面的指针全部置成null;所以说在容器里面vector< auto_ptr< int >> vec1; vec2(vec1),容器的拷贝构造和容器的赋值会引起vec1里面的指针全部置成nullptr
unique_ptr
unique_ptr<const unique_ptr<T>&> = delete;
unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;
unique_ptr和scoped_ptr一样都会把拷贝构造和赋值都和谐了,如果直接拷贝赋值就会报错。
c++11 右值引用 std::move得到当前变量的右值类型(右值引用的类型强转)
unique_ptr<int> p1(new int);
unique_ptr<int> p2(std::move(p1));
之所以unique_ptr可以成功是因为它带右值引用的拷贝构造函数和赋值运算符的重载函数
unique_ptr(unique_ptr<T> &&src)
unique_ptr<T>& operator=(unique_ptr<T> &&src)
带引用的智能指针
带引用技术的智能指针shared_ptr和weak_ptr 带引用计数:多个智能指针可以管理同一个资源 带引用计数:给每一个对象资源,匹配一个引用计数 智能指针 =》 资源的时候 =》 引用计数 + 1 智能指针 =》 不使用资源的时候 =》 引用计数 - 1 =》 != 0 0资源释放了
shared_ptr
// 自己实现share_ptr(线程不安全)
#include "iostream"
using namespace std;
#include "memory"
// 21点47分
template<typename T>
class RefCnt{
public:
RefCnt(T *ptr = nullptr)
: mptr(ptr){
if(mptr != nullptr){
mcount = 1;
}
}
void addRef() {mcount++;} // 添加引用计数
int delRef() {return --mcount;}
private:
T *mptr;
int mcount;
};
template <typename T>
class CSmartPtr{
public:
CSmartPtr(T *ptr = nullptr)
: mptr(ptr){
mpRefCnt = new RefCnt<T>(mptr);
}
// CSmartPtr(const CSmartPtr<T> &src){
// mptr = new T(*src.mptr);
// }
~CSmartPtr(){
if(0 == mpRefCnt->delRef()){
delete mptr;
mptr = nullptr;
}
}
T &operator* (){
return *mptr;
}
T *operator->(){
return mptr;
}
//重写拷贝构造
CSmartPtr(const CSmartPtr<T> &src)
:mptr(src.mptr), mpRefCnt(src.mpRefCnt)
{
if(mptr != nullptr){
mpRefCnt->addRef();
}
}
CSmartPtr<T>& operator=(const CSmartPtr<T> &src){
if(this == &src){
return *this;
}
if(mpRefCnt->delRef() == 0){
delete mptr;
}
mptr = src.mptr;
mpRefCnt = src.mpRefCnt;
mpRefCnt->addRef();
return *this;
}
private:
T *mptr;
RefCnt<T> *mpRefCnt;
};
int main(){
CSmartPtr<int> p1(new int );
CSmartPtr<int> p2(p1);
*p1 = 20;
cout << *p2;
}
线程安全 ++ – atomic_int
强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?
- shared_ptr:强智能指针 可以改变资源的引用计数
- weak_ptr:弱智能指针 不会改变资源的引用计数
- weak_ptr => shared_ptr => 资源(内存)
#include "iostream"
using namespace std;
#include "memory"
class B;
class A{
public:
A() {cout << "A()" << endl;}
~A() {cout << "~A()" <<endl;}
shared_ptr<B> _ptrb;
};
class B{
public:
B() {cout << "B()" << endl;}
~B() {cout << "~B()" <<endl;}
shared_ptr<A> _ptra;
};
int main(){
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->_ptrb = pb;
pb->_ptra = pa;
cout << pa.use_count() << endl;
cout << pb.use_count() << endl;
}
打印结果:
A()
B()
2
2
造成new出来的资源无法释放,资源泄露。
定义对象的时候,用强智能指针,引用对象的地方,使用弱智能指针
class B;
class A{
public:
A() {cout << "A()" << endl;}
~A() {cout << "~A()" <<endl;}
weak_ptr<B> _ptrb;
};
class B{
public:
B() {cout << "B()" << endl;}
~B() {cout << "~B()" <<endl;}
weak_ptr<A> _ptra;
};
打印:
A()
B()
1
1
~B()
~A()
weak_ptr
无法调用,没有提供operator* operator-> 解决 可以用把它提升为强智能指针
void func(){
// _ptra->testA();
shared_ptr<A> ps = _ptra.lock(); //提升方法
if(ps != nullptr){
ps->testA();
}
}
多线程访问共享对象的线程安全问题
#include "iostream"
#include "memory"
#include "thread"
using namespace std;
class A{
public:
A() {cout << "A()" << endl;}
~A() {cout << "~A()" <<endl;}
void testA() {cout << "非常好用的方法" << endl;}
};
void handler01(A *q){
std::this_thread::sleep_for(std::chrono::seconds(2));
q->testA();
}
int main(){
A *p = new A();
thread t1(handler01, p);
delete p;
t1.join();
}
//打印
A()
~A()
非常好用的方法!
这样非常不好 因为A对象都已经释放了,但是还是可以访问。所以q在访问A对象的时候,需要侦测一下A对象是否存活。
解决
#include "iostream"
#include "memory"
#include "thread"
using namespace std;
class A{
public:
A() {cout << "A()" << endl;}
~A() {cout << "~A()" <<endl;}
void testA() {cout << "非常好用的方法" << endl;}
};
void handler01(weak_ptr<A> p){
std::this_thread::sleep_for(std::chrono::seconds(2));
shared_ptr<A> sp = p.lock();
if(nullptr != sp){
sp->testA();
} else {
cout << "A对象已经析构, 不能在访问" <<endl;
}
}
int main(){
// A *p = new A();
{
shared_ptr<A> p(new A());
thread t1(handler01, weak_ptr<A>(p));
t1.detach();
}
std::this_thread::sleep_for(std::chrono::seconds(20));
return 0;
// delete p;
// t1.join();
}
//打印
A()
~A()
A对象已经析构, 不能在访问
|