01 基础知识
智能指针:保证能做到资源的自动释放;是利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放的。
// CSmartPtr<int> *p = new CSmartPtr<int>(new int); delete p;裸指针(在堆上)
template<typename T>
class CSmartPtr
{
public:
CSmartPtr(T *ptr=nullptr)
:mptr(ptr){}
~CSmartPtr()
{
delete mptr;
mptr = nullptr;
}
// 重载解引用操作符
T& operator*() { return *mptr; }
// 重载箭头操作符
T* operator->() { return mptr; }
private:
T* mptr;
};
堆内存管理示例(使用智能指针)
CSmartPtr<int> ptr1(new int);
堆内存管理示例(手动管理)
// data堆 heap堆 stack堆
int* p = new int(10);
*p = 10;
delete p;
auto_ptr
是C++98标准库中的智能指针类型,但由于其语义不明确且容易导致资源管理问题,它在C++11中被弃用。auto_ptr的问题主要在于其复制语义:复制一个 auto_ptr 会将资源的所有权从一个auto_ptr 转移到另一个,而不是复制资源。
scoped_ptr
是Boost库中的一种智能指针类型,它不支持复制和赋值操作,这意味着每个 scoped_ptr 都是唯一拥有资源的所有权。C++标准库中没有直接的 scoped_ptr,但可以使用类似的 unique_ptr
。
不带引用计数的智能指针
这些代码的目的是确保 scoped_ptr 和 unique_ptr 对象是唯一拥有其管理的资源的,并且不允许被复制,从而防止多个智能指针同时管理同一资源。
删除复制构造函数和复制赋值操作符
- 复制构造函数: 当一个对象被复制初始化(例如 scoped_ptr p2(p1);)时调用。
- 复制赋值操作符: 当一个对象被复制赋值(例如 p2 = p1;)时调用。
// C++11新标准:
// scoped_ptr
// 删除复制构造函数和复制赋值操作符
scoped_ptr(const scoped_ptr<T>&) = delete;
scoped_ptr<T>& operator=(const scoped_ptr<T>&) = delete;
// 推荐使用:
// unique_ptr
unique_ptr(const unique_ptr<T>&) = delete;
unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;
怎么解决浅拷贝的问题!!!
//CSmartPtr<int> p1(new int);
//CSmartPtr<int> p2(p1);
auto_ptr<int> ptr1(new int);
auto_ptr<int> ptr2(ptr1);
*ptr2 = 20;
cout << *ptr1 << endl;
// 不推荐使用auto_ptr进行vector<auto_ptr<int>> vec1; vec2(vec1);
// std::move => C++11 右值引用 std::move得到当前变量的右值类型
int main()
{
unique_ptr<int> p1(new int);
unique_ptr<int> p2(std::move(p1));
return 0;
}
02 shared_ptr和weak_ptr
带引用计数的智能指针shared_ptr
和weak_ptr
带引用计数:
- 多个智能指针可以管理同一个资源
- 给每一个对象资源,匹配一个引用计数;
智能指针 =》使用资源的时候 =》引用计数+1
智能指针 =》不使用资源的时候 =》引用计数-1 =》!=0 等于0时资源释放了
// 对资源进行引用计数的类
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()
{
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 (0 == mpRefCnt->delRef())
delete mptr;
mptr = src.mptr;
mpRefCnt = src.mpRefCnt;
mpRefCnt->addRef();
return *this;
}
private:
T* mptr; // 指向该资源的指针
RefCnt<T>* mpRefCnt; // 指向该资源引用计数对象的指针
};
int main()
{
CSmartPtr<int> ptr1(new int);
CSmartPtr<int> ptr2(ptr1);
CSmartPtr<int> ptr3;
ptr3 = ptr2;
*ptr1 = 20;
cout << *ptr2 << " " << *ptr3 << endl;
return 0;
}
03 shared_ptr的交叉引用问题
shared_ptr:强智能指针,可以改变资源的引用计数
weak_ptr:弱智能指针,不会改变资源的引用计数
operator* operator->
weak_ptr =>(观察) shared_ptr =>(观察) 资源(内存)
强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?
造成new出来的资源无法释放!!!资源泄露问题
定义对象的时候,用强智能指针;引用对象的地方,使用弱智能指针
class B;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
weak_ptr<B> _ptrb;
private:
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
weak_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;
return 0;
}
04 多线程访问共享对象的线程安全问题
C++开源网络库muduo库
多线程访问共享对象的线程安全问题
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "非常好用的方法!" << endl; }
};
// 子线程
void handler01(weak_ptr<A> pw)
{
std::this_thread::sleep_for(std::chrono::seconds(2));
// q访问A对象的时候,需要侦测以下A对象是否存活
shared_ptr<A> sp = pw.lock();
if (sp != nullptr)
{
sp->testA();
}
else
{
cout << "A对象已经析构,不能再访问!" << endl;
}
}
// main线程
int main()
{
{
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;
}
05 删除器
智能指针的删除器 deletor
智能指针:能够保证资源绝对的释放 delete ptr;
// unique_ptr shard_ptr
~unique_ptr(){ 是一个函数对象的调用 deletor(ptr);}
template<typename T>
class default_delete
{
public:
void operator()(T *ptr)
{
delete ptr;
}
};
template<typename T>
class MyDeletor
{
public:
void operator()(T* ptr)const
{
cout << "call MyDeletor.operator()" << endl;
delete[]ptr;
}
};
template<typename T>
class MyFileDeletor
{
public:
void operator()(T* ptr)const
{
cout << "call MyFileDeletor.operator()" << endl;
fclose(ptr);
}
};
int main()
{
// unique_ptr<int, MyDeletor<int>> ptr1(new int[100]); // delete []ptr;
// unique_ptr<FILE,MyFileDeletor<FILE>> ptr2(fopen("data.txt", "w"));
//lambda表达式 =》函数对象 function
unique_ptr<int, function<void(int*)>>ptr1(new int[100],
[](int* p)->void {
cout << "call lambda release new int[100]" << endl;
delete[]p;
});
unique_ptr<FILE, function<void(FILE*)>>ptr2(fopen("data.txt","w"),
[](FILE* p)->void {
cout << "call lambda release new fopen" << endl;
fclose(p);
});
return 0;
}