c++ make_shared & shared_ptr 小结

由于项目需求需要使用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

  1. 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;
    }

你可能感兴趣的:(c++ make_shared & shared_ptr 小结)