学不会的 吸佳佳 -- 智能指针

笔记 / 2020-10-18

传统指针

#include <iostream>
#include <memory>
#include <stdio.h>
using namespace std;

// 传统指针
void defaultAlloc(){
	int amtToStore;
	cout <<"How many numbers do you want to store : ";
	cin >>amtToStore;
	int* pNums;
	pNums = new int[amtToStore];
	if(pNums !=NULL){
		int i =0;
		while(i<amtToStore){
			cout <<"Enter a Number : ";
			cin >> pNums[i];
			i++;
		}
	}
	cout <<"You entered these numbers"<<endl;
	for(int i=0;i<amtToStore;i++){
		cout <<pNums[i]<<endl;
	}
	delete pNums;
}

int main(){
	defaultAlloc();
	return 0;
}

通常情况下我们使用上面的方式来分配空间.通过前面内存四区模型 我们知道 我们这里实在堆上面分配内存的,也就意味着需要我们手动去释放。当工程量大了之后我们很容易疏忽,忘记去释放内存,这时就会发生内存泄露问题,或者释放了一个正在使用的指针,从而造成非法内存,这些问题都是非常致命的,为了改善这一现状C++11 中引入了智能指针。

编译参数

g++ ..... -std=c++11

因为 智能指针是C++11引入的,所以我们在编译时,需要指定为 c++11

智能指针

在使用智能指针前,我们还需要引入一个头文件
#include<memory>

  • shared_ptr
  • unique_ptr
  • weak_ptr

shared_ptr

多个 shared_ptr 对象可以共同托管一个指针 p,当所有曾经托管 p 的 shared_ptr 对象都解除了对其的托管时,就会执行delete

  • get 获取当前托管的指针
  • reset 托管新的指针
#include <iostream>
#include <memory>

/*
 * @author luzhenfang
 * @date 2020 10 18
 * @desc modern cpp smartPointer
 */


class Elem {
protected:
    int mIndex;
public:
    Elem(int i) : mIndex(i) { std::cout << "Constructor : " << mIndex << std::endl; };

    virtual ~Elem() { std::cout << "Destructor : " << mIndex << std::endl; };

    int getElem() const { return mIndex; }
};


int main() {
    // shared_ptr

    // 一个指针 多个托管对象
    std::shared_ptr<Elem> sp1(new Elem(1));
    std::shared_ptr<Elem> sp2(sp1);
    std::shared_ptr<Elem> sp3;
    sp3 = sp2;

    std::cout << sp1->getElem() << std::endl;

    // 拿到托管指针
    auto p = sp2.get();
    std::cout << "p : " << p->getElem() << std::endl;
    // sp1 重新托管 E2
    sp1.reset(new Elem(2));
    // sp2 重新托管 E3
    sp2.reset(new Elem(3));
    // sp3 重新托管 E4 此时 E1 没人托管 被 delete
    std::cout <<"------"<<std::endl;
    sp3.reset(new Elem(4));
    // sp1 重新托管E5 导致 E2 没人托管 delete
    sp1.reset(new Elem(5));
    return 0;
}

unique_ptr

与 shared_ptr 不同,只能用 new 分配内存,独占不可共享

  • 不允许拷贝和赋值
#include <iostream>
#include <memory>
using namespace std;


int main(){
	// 智能指针
	int amtToStore;
	cout <<"How many numbers do you want to store : ";
	cin >>amtToStore;
	unique_ptr<int[]>pNums(new int[amtToStore]);
	if(pNums!=NULL){
		int i=0;
		while(i<amtToStore){
			cout <<"Enter a number : ";
			cin >>pNums[i];
			i++;
		}
	} 
	cout <<"Your entered these numbers "<<endl;
	for(int i=0;i<amtToStore;i++){
		cout <<pNums[i]<<endl;
	}

	return 0;
}

weak_ptr

主要用来解决循环引用问题

  • 弱引用 不会对计数叠加
  • 只能从 shared_ptr 或者 weak_ptr 构造而来
#include <iostream>
#include <memory>

/*
 * @author luzhenfang
 * @date 2020 10 18
 * @desc modern cpp smartPointer
 */



int main() {
    std::shared_ptr<std::string> sp1(new std::string("Hello CPP"));
    std::cout  <<"sp1 use_count "<<sp1.use_count()<<std::endl;
    std::weak_ptr<std::string>wp1(sp1);
    std::cout  <<"wp1 use_count "<<wp1.use_count()<<std::endl;

    std::weak_ptr<std::string>wp2(wp1);
    std::cout  <<"wp2 use_count "<<wp1.use_count()<<std::endl;
    // 没过期
    if (!wp2.expired()){
        auto sp2 =  wp2.lock();
        std::cout <<"sp2 " <<*sp2<<std::endl;
    }
    // 置空
    wp2.reset();
    // 过期了
    if (wp2.expired()){
        std::cout <<"wp2 expired"<< std::endl;
    }

    return 0;
}