一、概述

1. auto_ptr: c++11中推荐不使用他(放弃)

2. shared_ptr: 每添加一次引用 就+1,减少一次引用,就-1;做到指针进行共享

3. unique_ptr: 一个指针同时只能有一个使用者使用

4. weaked_ptr: 与shared_ptr搭配使用

二、详细说明

1. shared_ptr
为T类型的变量定义std::shared_ptr<T>共享指针

shared_ptr内部维护了资源引用数量的计数器。当不再有shared_ptr指向资源时,资源将自动被析构。默认调用delete函数。

使用资源时直接对共享指针 * 运算符解引用即可。

#include<cstdio>
#include<memory>
 
int main()
{
    std::shared_ptr<int> sp(new int(10));
    std::shared_ptr<int> sp2 = sp;
    printf("Shared_ptr=%p, Count=%d\n", sp.get(), sp.use_count());
    printf("Shared_ptr=%p, Count=%d\n", sp2.get(), sp2.use_count());
    sp.reset(); //sp取消引用
    printf("Shared_ptr=%p, Count=%d\n", sp2.get(), sp2.use_count());
    getchar();
    return 0;
}
运行结果:

Shared_ptr=00BA7AD8, Count=2
Shared_ptr=00BA7AD8, Count=2
Shared_ptr=00BA7AD8, Count=1

 

2. unique_ptr
unique_ptr实现的是以前auto_ptr类似的功能。

与shared_ptr可以使用多个指针引用资源不同的是,unique_ptr意味着资源最多只能由一个指针进行引用。用另外一个unique_ptr指针取代先前的指针时,先前的指针将被强制修改为nullptr,对该指针解引用将导致程序异常。

这时必须注意unique_ptr的赋值只能接受右值引用,否则编译报错。可以使用std::move()将左值转换为右值引用。

 

可以使用调用delete的默认std::unique_ptr<T>构造,也可以使用std::unique_ptr<T, class Delete>调用自己的释放资源的函数。

示例程序使用了后者,实现文件在各种不同情况下都能够正确关闭,避免了多次或者忘记了调用fclose()。

#include<cstdio>
#include<fstream>
#include<memory>
 
void close_file(std::FILE *fp) {
    std::fclose(fp);
    printf("File closed.\n");
}
 
int main()
{
    //std::auto_ptr<int> ap(new int(11));
    //printf("Auto_ptr=%X\n", ap);
    //std::auto_ptr<int> nap=ap;
    //printf("Old_Auto_ptr=%X\n", ap); //指向的内容被抢夺了
    
    std::ofstream("test.txt") << "!";
 
    {
        std::unique_ptr<FILE, decltype(&close_file)> fp(std::fopen("test.txt", "r"), &close_file);
        auto fp2 = std::move(fp);
        //auto fp3 = fp; unique_ptr赋值运算符支持右值引用,不能使用左值
        printf("Old_one=%p, New_one=%p\n", fp.get(), fp2.get());
        if (fp2) {
            printf("Get '%c'.\n", fgetc(fp2.get()));
        }
    }
    getchar();
    return 0;
}
运行结果:

Old_one=00000000, New_one=00BE78A8
Get '!'.
File closed.

可以看到,在退出了fp的作用域之后,文件被自动关闭了。

3. weak_ptr

weak_ptr是弱智能指针对象,它不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的智能指针。将一个weak_ptr绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。一旦最后一个所指向对象的shared_ptr被销毁,所指向的对象就会被释放,即使此时有weak_ptr指向该对象,所指向的对象依然被释放。

C++ 智能指针

代码验证如下:

//default consstructor
weak_ptr<string> wp;

{
    shared_ptr<string> p = make_shared<string>("hello world!\n");
    //weak_ptr对象也绑定到shared_ptr所指向的对象。
    wp = p;   
    cout << "use_count: " <<wp.use_count() << endl;
}
//wp是弱类型的智能指针,不影响所指向对象的生命周期,
//这里p已经析构,其所指的对象也析构了,因此输出是0
cout << "use_count: " << wp.use_count() << endl;

运行结果:

use_count: 1
use_count: 0

weak_ptr智能指针使用如下:

void test_valid(weak_ptr<string> &wp)
{
    if(shared_ptr<string>  smptr2 = wp.lock())
    {
        cout << "the shared_ptr is valid\n";
    }
    else
    {
        cout << "the shared_ptr is not valid\n";
    }

    //检查被引用的对象是否已删除 false 仍存在  true 释放
    if(!wp.expired())
    {
        //it is getting valid shared_ptr obj now;
        shared_ptr<string>  smptr1 = wp.lock();
        cout << "   get obj value: " << *smptr1;
    }
}

int main()
{    
    shared_ptr<string> p = make_shared<string>("hello world!\n");

    //default consstructor
    weak_ptr<string> wp1;

    //copy constructor
    weak_ptr<string> wp2(p);

    //assign constructor
    weak_ptr<string> wp3 = wp2;

    test_valid(wp2);

    //释放被管理对象的所有权, 调用后 *this 不管理对象
    wp2.reset();

    test_valid(wp2);

    return 0;
}

运行结果:

the shared_ptr is valid
    get obj value: hello world!
the shared_ptr is not valid

循环引用

C++ 智能指针

weak_ptr可以解决shared_ptr循环引用问题,导致内存泄漏问题,问题模型如下图:

当shared_ptr类型的spA、spB对象析构时,ref_count 减一;由于Obj A 和 Obj B中的shared_ptr智能指针还相互引用,导致ref_count不为零,spA和spB不会去析构所指的对象,最终导致内存泄漏。

当Obj A 和 Obj B中的智能指针是weak_ptr是,不会影响share_ptr智能指针引用计数,当spA和spB析构时,导致ref_count为零,同时所指向的对象也就被析构了;其解决方案模型如下: 

C++ 智能指针
代码实例如下:

//strong reference
class B;
class A
{
public:
    shared_ptr<class B> m_spB;
};


class B
{
public:
    shared_ptr<class A> m_spA;
};

//weak reference
class WeakB;
class WeakA
{
public:
    weak_ptr<class WeakB> m_wpB;
};


class WeakB
{
public:
    weak_ptr<class WeakA> m_wpA;
};


void test_loop_ref()
{
    weak_ptr<class A> wp1;

    {
        auto pA = make_shared<class A>();
        auto pB = make_shared<class B>();

        pA->m_spB = pB;
        pB->m_spA = pA;

        wp1 = pA;    
    }//内存泄漏

    cout << "wp1 reference number: " << wp1.use_count() << "\n";

    weak_ptr<class WeakA> wp2;
    {
        auto pA = make_shared<class WeakA>();
        auto pB = make_shared<class WeakB>();

        pA->m_wpB = pB;
        pB->m_wpA = pA;

        wp2 = pA;
    }//无内存泄漏

    cout << "wp2 reference number: " << wp2.use_count() << "\n";
}

int main()
{    
    //std::weak_ptr 用来避免 std::shared_ptr 的循环引用
    test_loop_ref();

    return 0;
}
wp1和wp2作为shared_ptr智能指针的核查器,其检测结果如下:

wp1 reference number: 1//内存泄漏
wp2 reference number: 0//问题解决
 

 

相关文章:

  • 2021-07-26
  • 2021-10-02
  • 2021-06-13
猜你喜欢
  • 2022-12-23
  • 2021-11-18
  • 2021-09-16
  • 2021-12-02
相关资源
相似解决方案