c++之智能指针(一)之动态内存与智能指针

来源:互联网 发布:asmr德叔是哪国人 知乎 编辑:程序博客网 时间:2024/06/12 18:50

动态内存与智能指针

在c++中,动态内存的管理是通过一对运算符来完成的:new: 在动态内存中为对象分配空间并返回一个指向该对象的指针。delete: 接受一个动态对象的指针并销毁该对象,并释放与之关联的内存。

例子

   //新建一个动态数组,元素个数为960*520,array是一个指针,指向数组的第一个int    int *array = new int[960*520];    delete [] array;//释放动态数组,方括号是必须的,因为我们当时分配的是一个数组

从上面的代码段可以看出,我们如果使用new来给对象动态分配空间的话,一定要记得对象用完之后使用delete释放空间,在这种情况下,会有内存泄露的风险。有时,在尚有指针引用内存的情况下,我们就释放了他,这个时候会产生引用非法内存的指针。

为了更安全的使用指针,标准库提供了智能指针 来管理动态对象。
1. shared_ptr: 允许多个指针指向同一个对象
2. unique_ptr: 指针独占所指向的对象
3. weak_ptr: 弱引用,指向shared_ptr 所指向的对象

这三种类型都定义在memory头文件中。

shared_ptr类

创建

类似vector,智能指针也是模板。所以我们在创建智能指针的时候,必须提供额外的信息—-智能指针所指向的类型。

例子

//动态分配内存,使p1指向值为hello world的stringshared_ptr<string> p1 = make_shared<string>("hello world");//如果p1不为空,检查它指向的是不是一个空的stringif (p1 && p1->empty()){    *p1 = "string";//解引用p1,将一个新值赋予p1} //p2指向一个值为2的intshared_ptr<int> p2 = make_shared<int>(2);//p3 指向一个值初始化的int,即值为0shared_ptr<int> p3 = make_shared<int>();

使用make_shared来创建智能指针时,其传递的参数必须与给定类型的对象的某个构造函数像匹配。

可以使用auto 来保存make_shared的结果:

auto p4 = make_shared<string>(10, '9');

拷贝和赋值

每个shared_ptr都有一个关联的计数器,通常称为引用计数
拷贝一个智能指针的时候,会出现引用计数递增的情况:
1. 使用shared_ptr初始化另一个shared_ptr
2. 将其传递给另一个函数
3. 作为函数的返回值

计数器递减的情况:
1. 给shared_ptr赋予一个新值
2. shared_ptr被销毁(局部的shared_ptr离开其作用域)

 auto p4 = make_shared<string>(10, '9');//p4指向的对象只有一个引用者 p1 = p4;//给p1赋值,另它指向另一地址(p1和p4指向同一个对象) //递增p4指向对象的引用计数//递减p1 原来指向对象的引用计数//p1原来指向的对象已经没有引用者,会自动释放

当引用计数变为0时,shared_ptr会自动销毁此对象。是通过对象的析构函数完成销毁工作的。

class A{public:    A(){        cout << "construct A" << endl;    }    ~A(){        cout << "destruct A" << endl;    }};shared_ptr<A> getA(){    return make_shared<A>();}void dosthWithA(shared_ptr<A> a){}int main(){    shared_ptr<A> a = getA();    dosthWithA(a);    return 0;}

这里写图片描述

可以看出,创建只能指针的时候,自动执行了函数的构造函数,当main函数执行完毕之后,再也没有人引用A对象了,自动调用析构函数,销毁对象。

使用了动态生存期资源的类

程序使用动态内存一般有以下几种原因:
1. 程序不知道自己使用多少对象
2. 程序不知道所需对象的准确类型
3. 程序需要在多个对象间共享数据

容器类是出于第一种原因而是用动态内存的例子。

对象共享数据:

    vector<string> v1;    {        vector<string> v2 = { "a", "b", "c" };        v1 = v2;//从v2拷贝元素到v1中    }//v2被销毁,其中的元素也被销毁    //v1有三个元素,是原来v2中元素的拷贝

由一个vector分配的元素只有当这个vector存在的时候才存在。当一个vector销毁的时候,这个vector中的元素也被销毁。

为了共享对象数据,我们希望原对象机器拷贝应该引用相同的底层元素。比如说下面的代码:

Blog<string>b1;    {        Blob<string>b2 = { "a", "b" };        b1 = b2;//b1和b2共享相同的元素    }//b2销毁了,但是b2中的元素不能销毁    //b1指向最初由b2创建的元素

但是该如何实现呢?为了保证b2离开其作用域时,其中的vector的元素继续存在不被销毁,我们将vector保存在动态内存中。

class StrBlob {public:    typedef std::vector<std::string>::size_type size_type;    // constructors    StrBlob() : data(std::make_shared<std::vector<std::string>>()) { }    StrBlob(std::initializer_list<std::string> il);    // size operations    size_type size() const { return data->size(); }    bool empty() const { return data->empty(); }    // add and remove elements    void push_back(const std::string &t) { data->push_back(t); }    void pop_back();    // element access    std::string& front();    std::string& back();private:    std::shared_ptr<std::vector<std::string>> data;//保存在动态内存中    // throws msg if data[i] isn't valid    void check(size_type i, const std::string &msg) const;};

StrBlob类只有一个数据成员,它是shared_ptr类型。当我们拷贝、赋值或销毁一个StrBlob对象时,它的shared_ptr成员也会被拷贝、赋值或销毁。对于由StrBlob函数构造分配的vector,当最后一个指向他的StrBlob对象被销毁时,它会随之被自动销毁。

原创粉丝点击