注
由于项目需求需要使用c++, 特意写点学习笔记, 以下例子均来自网友分享的
资料, 如果原作者觉得有损您的利益, 请通知本人进行删除.
make_shared & shared_ptr
typedef struct _StructA StructA;
typedef struct _StructB StructB;
struct _StructA
{
int i;
std::shared_ptr pStructB;
_StructA(): i(int())
{
printf("_StructA alloc \n");
};
~_StructA()
{
printf("_StructA dealloc \n");
};
} ;
struct _StructB
{
int i;
std::shared_ptr pStructA;
_StructB(): i(int())
{
printf("_StructB alloc \n");
};
~_StructB()
{
printf("_StructB dealloc \n");
};
};
- make_shared 和 shared_ptr 的用处
// make_shared 和 shared_ptr 设计初衷是引入引用计数这个概念来减少程序
// 员的工作量. 他的设计想法跟 Objective-c 的引用计数有点类似。请看以下代码:
int main(int argc, const char * argv[])
{
printf("----- start ----- \n");
std::shared_ptr pA = std::make_shared();
std::shared_ptr pB (new StructB());
printf("----- end ----- \n");
return 0;
}
// 打印结果
**----- start ----- **
**_StructA alloc **
**_StructB alloc **
**----- end ----- **
**_StructB dealloc **
**_StructA dealloc **
通过实验可以看出, 超出作用域之后就会对 shared_ptr 所作用的对象进行引用计数减少1, 如果发现 shared_ptr 所作用的对象引用计数为0则说明,这个对象需要释放内存.
- 环形引用
printf("----- start ----- \n");
std::shared_ptr pA = std::make_shared();
std::shared_ptr pB = std::make_shared();
pA->pStructB = pB;
pB->pStructA = pA;
printf("----- end ----- \n");
// 打印结果
**----- start ----- **
**_StructA alloc **
**_StructB alloc **
**----- end ----- **
环形应用: 就是对象 A 持有对象 B 的强引用, 对象 B 持有对象 A 的强应用,最终导致 A 和 B 都无法释放。
// 解决方法, 其中一方使用弱引用
struct _StructB
{
int i;
// 改为弱引用, 同理针对 StructA 也可以这样做
std::weak_ptr pStructA;
// std::shared_ptr pStructA;
_StructB(): i(int())
{
printf("_StructB alloc \n");
};
~_StructB()
{
printf("_StructB dealloc \n");
};
};
- make_shared 和 shared_ptr 区别
/**
* 1. 执行申请 数据体(StructA) 的内存申请
* 2. 执行控制块的内存申请
*/
std::shared_ptr pA1(new StructA());
/**
* 数据体 和 控制块的 内存一块申请
*/
std::shared_ptr pA2 = std::make_shared();
- make_shared 和 shared_ptr 如何选择
void fun(std::shared_ptr pA, std::shared_ptr pB)
{
printf("pA->i = %d pB->i = %d \n", pA->i, pB->i);
}
int main(int argc, const char * argv[])
{
/**
* 因为C++允许参数在计算的时候打乱顺序,因此可能出现以下顺序
* 1. new StructA
* 2. new StructB // 如果在此步出现问题, 那么就会导致 1. 所产生的内存无人管理, 造成内存泄露
* 3. shared_ptr A
* 4. shared_ptr B
*/
fun(std::shared_ptr(new StructA()), std::shared_ptr(new StructB()));
return 0;
}
// 解决方法1
auto pSA = std::shared_ptr(new StructA());
auto pSB = std::shared_ptr(new StructB());
fun(pSA, pSB);
// 解决方法2
fun(std::make_shared(), std::make_shared());
. weak_ptr
- weak_ptr 主要是用来判断 shared_ptr 所指向的数据内存是否存在, 因为make_shared 只作一次内存分配, shared_ptr 可以把这种内存分配分为两个步骤, weak_ptr 可以通过 lock 来判断 shared_ptr 所指向的数据内存是否被释放
std::shared_ptr pSA(new StructA());
std::weak_ptr wPSA = pSA;
pSA.reset(new StructA());
auto p = wPSA.lock();
std::cout<< p << std::endl;
std::cout<< wPSA.use_count() << std::endl;
// 打印结果
**_StructA alloc **
**_StructA alloc **
**_StructA dealloc **
**0x0**
**0**
**_StructA dealloc **
- weak_ptr 使用注意
// 主线程
std::shared_ptr pSA(new StructA());
std::weak_ptr wPSA(pSA);
// 子线程 1
pSA.reset(new StructA());
// 子线程 2
// 错误做法, 现在编译器好像也不允许这么做
// StructA *p = wPSA.get();
// if ( p )
// {
// p->i = 5;
// }
// 正确做法
if ( auto p = wPSA.lock() )
{
p->i = 5;
}