c++智能指针介绍之shared_ptr

c++智能指针介绍之shared_ptr


  • c++11引入,头文件<memory>, 引用计数实现的智能指针,多个智能指针指向同一资源,累加资源的引用计数。

特性

1 支持赋值,拷贝构造

  • 构造函数时explicit
template< class Y > 
shared_ptr( const shared_ptr<Y>& r ) noexcept; // 左值拷贝构造
shared_ptr( shared_ptr&& r ) noexcept; // 右值拷贝构造
shared_ptr& operator=( const shared_ptr& r ) noexcept; // 赋值运算符
T* get() const noexcept; // 返回原始指针
long use_count() const noexcept // 返回引用计数值
shared_ptr<Base> sp(new Son(2222, "ddddddddd"));
shared_ptr<Base> sp2(new Son(2222, "ddddddddd"));
sp = sp2;  // 支持复制操作,sp原来对象释放,sp2引用计数+1
cout << sp2.use_count() << endl;  // use_count返回引用计数值 为2
// 构造函数时explicit的
shared_ptr<int> clone(int p) {
	return new int(p); // 错误,不能发生隐式转化
}

2 unique/make_shared

  • unique()如果use_count为1则返回true,否则为false
  • make_shared<T>()代替new创建shared_ptr对象; 注意make_shared有 不能使用删除器,一次分配内存,异常安全等特点
shared_ptr<Base> sp3 = make_shared<Base>(2432, "dfaf"); // 类似emplace,直接传构造函数的参数
sp3->print();	
cout << sp3.unique() << endl; // 返回true:1

3 引用计数/get/release/use_count

  • shared_ptr对象作为函数返回值时、拷贝构造、赋值操作都会时引用计数增加
  • get/release返回内置指针
  • use_count返回引用计数值
shared_ptr<int> ap(new int(2)); // 1
shared_ptr<int> ap2(ap); // 拷贝构造,2
shared_ptr<int> ap3;
ap3 = ap2; // 复制操作 3
cout << ap3.use_count() << endl; //3

4 删除器

  • 可以自定义 删除器,reset转移控制权;
  • unique_ptr不同,shared_ptr不支持数组操作,但是可以使用指针和lambda自定义删除器来管理数组对象
shared_ptr<int> sp(new int[3] {3,2,3}, [](int *p){ cout << p[2]<< endl; delete []p;});
  • 注意和unique_ptr的区别,unique_ptr的删除器需要在类型处指出并传递删除器实参,shared_ptr不用指出类型
shared_ptr<T> p<q, d> // 自定义删除器d
p.reset<q, d2> // p接管q的资源,同时指定删除器为d2
class Base {
public:
    Base(int age, string name) : age_(age), name_(name) {
        cout << "Base 构造" << age_ << name_ <<  endl;
    };
     virtual ~Base() {
        cout << "Base 析构" << age_ << name_ <<  endl;
    }
public:
    int age_;
    string name_;
};

auto del = [](Base *base){
	delete base;
}
// 与unique_ptr的区别
shared_ptr<Base> sp(new Base(333, "xxx"), del); 
unique_ptr<Base, decltype(del)> up(new Base(333, "xxx"), del):

5 移动属性

  • 移动构造:转移了资源所有权,移动构造一个新的对象时,原来的对象引用减少,同时新对象对资源引用增加,一加一减,引用计数不变,只是资源的控制权转向了新的对象;但是移动属性带来的好处是比复制快。
shared_ptr<Base> sp3 = make_shared<Base>(2432, "dfaf");
shared_ptr<Base> sp4(std::move(sp3));
cout << sp4.use_count() << endl; // 1
cout << sp3.use_count() << endl; // 0

6 shared_ptr 内存占用

  • shared_ptr对象的尺寸是裸指针的两倍,因为内部除了裸指针还有引用计数器的指针
  • shared_ptr的内存分为两块
    • 裸指针T的对象地址
    • 控制块指针
      指向的控制块包含 引用计数、弱计数器、其他数据如自定义删除器指针、自定义分配器指针等。
  • make_shared总是会创建一个控制块,从unique_ptr对象、auto_ptr对象出发创建一个shared_ptr时也会创建一个控制块,当使用裸指针来构造一个shared_ptr时也会创建一个控制块。
    • 不能将一个裸指针传递给两个shared_ptr,因为这样有两个控制块,两个控制块对资源管理,造成两次释放资源或者一边释放资源后另外一边依然在使用这个已经释放的资源。

备注:

  • 多态,父类智能指针保存子类对象,父类析构不能为virtual也会调用多态
class Base {
public:
    Base(int age, string name) : age_(age), name_(name) {
        cout << "Base 构造" << age_ << name_ <<  endl;
    };
     virtual ~Base() {
        cout << "Base 析构" << age_ << name_ <<  endl;
    }
public:
    int age_;
    string name_;
};

class Son : public Base {
public:
    Son(int age, string name) : Base(age, name) {
        cout << "Son 构造" << age_ << name_ <<  endl;
    };
    ~Son() {
        cout << "Son 析构" << age_ << name_ <<  endl;
    }
};

// 如果父类析构不virtual,也会多态释放内存
shared_ptr<Base> p1(new Son(2, "xxx"));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值