C++中的智能指针

智能指针的概念:

C++中堆内存对象在new之后创建,但是如果忘记delete则会产生内存泄露的问题。诸如Java、C#等语言则直接提供垃圾回收机制来处理不使用的对象,因此在C++98标准中引入了智能指针的概念,并在C++11中趋于完善

使用智能指针,可以让堆内存对象无需手动调用delete就能销毁

智能指针对象是一个栈内存对象,但是它可以管理一个堆内对象,在智能指针对象销毁时,自动触发析构函数,在析构函数中销毁被管理的堆内存对象,从而防止堆内存对象的内存泄露

根据智能指针拷贝/赋值处理不同,可以分为三种实现形式:

(1)拷贝/赋值时分配新的地址空间,拷贝原指针指向的内容

(2)拷贝/赋值时将右边的空间和地址传递给左边,右边会是失去原来的地址空间

(3)拷贝/赋值是共享地址空间,同时增加一个引用计数(记录使用地址空间的对象个数),当引用计数为0的时候释放地址空间

C++11中有四种智能指针:

后三着是C++11支持的内容,第一个已经被C++11弃用,因此不推荐使用

注意:

智能指针类的使用需要引入头文件 #include <memory>

(1)std::auto_ptr

auto_ptr是C++98的智能指针,目前已经不推荐使用

示例代码:
#include <iostream>
#include <memory> // 头文件

using namespace std;

class Test
{
public:
    Test(string name):name(name)
    {
        cout << name << "构造函数" << endl;
    }

    void show()
    {
        cout << name << "成员函数" << endl;
    }

    ~Test()
    {
        cout << name << "析构函数" << endl;
    }

private:
    string name;
};

int main()
{
    {
        cout << "{" << endl;

        Test *t1 = new Test("A");
        // 创建智能指针对象ap1,并管理资源对象A
        auto_ptr<Test> ap1(t1);
//        delete t1; 错误
        cout << ap1.get() << " " << t1 << endl; // 0x1232468 0x1232468
        // 通过智能指针对象调用被管理对象的成员
        ap1.get()->show();
        // 创建智能指针对象ap2,并管理资源对象B
        auto_ptr<Test> ap2(new Test("B"));
        // 使用资源对象C顶替掉ap2中的B
        ap2.reset(new Test("C")); // B被顶替,销毁
//        ap2.release(); // 释放对资源对象的管理,且不销毁资源对象
        ap2.reset(); // 释放对资源对象的管理,且销毁资源对象

        cout << "}" << endl;
    }

    cout << "主函数结束" << endl;
    return 0;
}
auto_ptr被废弃的原因:

与之前的浅拷贝类似,当auto_ptr面临复制语义时(拷贝构造函数、赋值运算符等)会出现对资源对象的控制权转移问题

(2)std::unique_ptr

作为对auto_ptr的改进,unique_ptr对其持有的堆内存资源具有唯一控制权,即unique_ptr不可以通过传统语法复制

示例代码:
#include <iostream>
#include <memory> // 头文件

using namespace std;

class Test
{
public:
    Test(string name):name(name)
    {
        cout << name << "构造函数" << endl;
    }

    void show()
    {
        cout << name << "成员函数" << endl;
    }

    ~Test()
    {
        cout << name << "析构函数" << endl;
    }

private:
    string name;
};

int main()
{
    {
        cout << "{" << endl;

        unique_ptr<Test> up1(new Test("A"));
        unique_ptr<Test> up2(new Test("B"));

//        unique_ptr<Test> up3(up1); 错误
        unique_ptr<Test> up4;
//        up4 = up2; 错误

        up1.get()->show();
        up2.get()->show();

        cout << "}" << endl;
    }

    cout << "主函数结束" << endl;
    return 0;
}

unique_ptr可以使用move函数完成控制权的转移,提升了语法门槛,降低无意中转移的概率。

(3)std::shared_ptr

unique_ptr对资源具有独占性,而shared_ptr可以把资源对象在多个shared_ptr之间进行共享

shared_ptr有两种初始化对象的方法:

(1)资源对象使用new

(2)使用make_shared函数

示例代码:
#include <iostream>
#include <memory> // 头文件

using namespace std;

class Test
{
public:
    Test(string name):name(name)
    {
        cout << name << "构造函数" << endl;
    }

    void show()
    {
        cout << name << "成员函数" << endl;
    }

    ~Test()
    {
        cout << name << "析构函数" << endl;
    }

private:
    string name;
};

int main()
{
    {
        cout << "{" << endl;

        // 使用new初始化
        shared_ptr<Test> sp1(new Test("A"));
        // 使用make_shared函数初始化
        shared_ptr<Test> sp2 = make_shared<Test>("B");

        sp1.get()->show();
        sp2.get()->show();

        cout << "}" << endl;
    }

    cout << "主函数结束" << endl;
    return 0;
}

这两种初始化防止各有利弊,后者相对前者:

(1)性能更好

(2)更加安全

(3)内存释放效率低

(4)std::weak_ptr

weak_ptr是对资源的一种弱持有的关系,本身无法影响资源对象的销毁,只是为了协助shared_ptr进行工作,因此也不会影响计数。

示例代码:
#include <iostream>
#include <memory> // 头文件

using namespace std;

class Test
{
public:
    Test(string name):name(name)
    {
        cout << name << "构造函数" << endl;
    }

    void show()
    {
        cout << name << "成员函数" << endl;
    }

    ~Test()
    {
        cout << name << "析构函数" << endl;
    }

private:
    string name;
};

int main()
{

    shared_ptr<Test> sp1 = make_shared<Test>("A");
    {
        cout << "{" << endl;

        weak_ptr<Test> wp1;
        cout << wp1.use_count() << endl; // 0
        wp1 = sp1; // 赋值运算符(其它的复制语义也可以)
        cout << sp1.use_count() << " " << wp1.use_count() << endl; // 1 1
//        wp1.get(); 错误

//        sp1.reset(); // 释放控制权,并减少引用计数1,如果1→0,则销毁

        if(wp1.expired()) // 失效性检测
        {
            cout << "wp1抱的大腿没了!!" << endl;
        }else
        {
            // 从“备胎”里,获取一个sp对象
            shared_ptr<Test> sp2 = wp1.lock();
            cout << sp1.use_count() << " "
                 << wp1.use_count() << " " << sp2.use_count() <<  endl; // 2 2 2

            sp2.get()->show();

            // lock函数可以反复使用
            shared_ptr<Test> sp3 = wp1.lock();
            cout << sp3.use_count() << endl; // 3

            wp1.lock(); // 未保存返回值
            cout << sp3.use_count() << endl; // 3
        }
        cout << sp1.use_count() << endl; // 1

        cout << "}" << endl;
    }
    cout << sp1.use_count() << endl; // 1

    cout << "主函数结束" << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值