智能指针

c++难点之一就是要比较关注内存管理的问题,如果内存不及时释放就会造成内存泄漏。智能指针出现之前,程序员都是手动释放已经申请的堆内存,但有时候比较容易忘记,也有可能就是程序执行异常了,导致释放内存的代码没有执行,例如以下代码就需要自己手动释放内存。

class Test1206
{
public:
    Test1206(const char *str)
    {
        int len = strlen(str);
        p = new char[len+1];
        strncpy(p, str, len);
        p[len] = '\0';
        cout << "test1206 constructed" << endl;
    }
    ~Test1206()
    {
        delete p;//手动释放
        cout << "test1206 deconstructed" << endl;
    }

    void print()
    {
        cout << p << endl;
    }

private:
    char *p = NULL;
};


int main()
{
    Test1206 *t = new Test1206("Hello,World!");
    t->print();
    delete t;//手动释放

    return 0;
}

总之手动释放内存很容易导致内存泄漏。智能指针就是用来解决手动释放内存的问题的,比较常用的智能指针就是share_ptr。

(1) shared_ptr(存在线程安全问题)

struct test_shared_ptr_t
{
    ~test_shared_ptr_t()
    {
        cout << "destructed" << endl;
    }
    int a = 0;
    int b = 0;
    int c = 0;
};

int main()
{
    shared_ptr<int> ptr = make_shared<int>(2);//自动释放内存 如果不填2 会有一个默认的值
    cout << ptr.get() << " " << *(ptr.get()) << " " <<*ptr << endl;

    shared_ptr<test_shared_ptr_t> ptr2(new test_shared_ptr_t);//自动释放内存
    cout << ptr2.get() << " " << ptr2->a << " " << ptr2->b << " " << ptr2->c << endl;

    return 0;
}

程序输出为:

0000022A86CE9F80 2 2
0000022A86CEFE60 0 0 0
destructed

从上面的程序可以发现,shared_ptr指针有两种初始化的方式,一种是通过make_shared(推荐使用这次方式),另外一种是通过把new出来的指针传给shared_ptr的构造函数。比较有意思的是智能指针ptr既可以使用.运算符也可以使用->运算符。

class TestSharePtr
{
public:
    void insert_data()
    {
        auto tmp = make_shared<test_shared_ptr_t>();
        tmp->a = 10;
        tmp->b = 10;
        tmp->c = 10;

        share_map.insert(std::make_pair(10, tmp));
    }
    void delete_data()
    {
        if (share_map.count(10)) {
            share_map.erase(10);
            std::cout << "erase data" << std::endl;
        }
    }

    ~TestSharePtr()
    {
        std::cout << "test_share_ptr deleted!" << std::endl;
    }
    std::map<int, std::shared_ptr< test_shared_ptr_t>> share_map;
};


int main()
{
    TestSharePtr tst;
    tst.insert_data();
    while (1) {
        Sleep(1000);
        tst.delete_data();
    }

    return 0;
}

从上面的例子可以发现erase智能指针对象的时候会自动调用构造函数。

struct test_shared_ptr_t
{
    ~test_shared_ptr_t()
    {
        cout << "test_shared_ptr_t destructed" << endl;
    }
    int a = 0;
    int b = 0;
    int c = 0;
};


class TestSharePtr
{
public:
    TestSharePtr()
    {
        test1 = std::make_shared<test_shared_ptr_t>();
        test2 = new test_shared_ptr_t;
    }
    ~TestSharePtr()
    {
        std::cout << "TestSharePtr deleted!" << std::endl;
        delete test2;
    }
    std::shared_ptr<test_shared_ptr_t> test1;
    test_shared_ptr_t* test2;
};


int main()
{
    TestSharePtr tst;    

    return 0;
}

从上例可以看出来,tst析构的时候,会自动调用其类成员test1的构造函数,释放对应的内存空间,但是test2却不会,需要手动delete。

(2)auto_ptr

在c++11中已废弃,被unique_ptr所代替,原因是转移指针所有权时(不会报错),再去引用以前的auto_ptr会导致程序崩溃

(3)unique_ptr

没有引用计数器,保证一个对象只被一个unique_ptr指向它(多个会报错),不能使用赋值转移(会报错),但是可以使用move移动转移或者移动构造。

(4)weak_ptr

它一般是配合shared_ptr使用,weak_ptr不会增加引用计数,用来解决shared_ptr循环引用时,内存泄漏的问题。

class CB;
class CA;


class CA
{
public:
    CA() {}
    ~CA() { std::cout << "A destructed" << std::endl; }

    void Register(const std::shared_ptr<CB>& sp)
    {
        m_sp = sp;
    }

private:
    std::shared_ptr<CB> m_sp; //改为weak_ptr则不会有循环引用的问题
};

class CB
{
public:
    CB() {};
    ~CB() { std::cout << "B destructed" << std::endl; };

    void Register(const std::shared_ptr<CA>& sp)
    {
        m_sp = sp;
    }

private:
    std::shared_ptr<CA> m_sp;
};


int main()
{
    std::shared_ptr<CA> spa(new CA);
    std::shared_ptr<CB> spb(new CB);

    spb->Register(spa);
    spa->Register(spb);
    printf("%d,%d\n", spb.use_count()); // 2
    printf("%d,%d\n", spa.use_count()); // 2

    return 0;
}
 

参考资料:

http://c.biancheng.net/view/7898.html 使用

https://www.cnblogs.com/zeppelin5/p/10083597.html

https://blog.csdn.net/shaosunrise/article/details/85228823

https://blog.csdn.net/kof0101/article/details/51884634

https://www.jianshu.com/p/c6b7b4e15f9d

https://blog.csdn.net/mayh554024289/article/details/96874719

https://blog.csdn.net/qq_22642239/article/details/102667553

https://blog.csdn.net/fengbingchun/article/details/52202007

https://blog.csdn.net/worldwindjp/article/details/18843087 实现

https://www.cnblogs.com/wxquare/p/4759020.html

https://www.cnblogs.com/diysoul/p/5930361.html

https://blog.csdn.net/yagerfgcs/article/details/72886630

https://blog.csdn.net/CPriLuke/article/details/79462791

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值