zoukankan      html  css  js  c++  java
  • 第12章 动态内存

    全局对象:启动时分配,结束时销毁

    局部对象:程序块内分配,程序块外销毁

    static对象:第一次使用分配,结束时销毁

    动态内存使用new来分配对象,使用delete销毁对象

    12.1两种智能指针

    #include<memory>

    shared_ptr: 多个指针可以指向同一个对象

    unique_ptr: 独占指向的对象

            weak_ptr: 一个伴随类,指向shared_ptr管理的对象,是弱引用

    智能指针也是模板,定义时需要指明类型

    shared_ptr<string> p1;

    shared_ptr<list<int>> p2;

    默认初始化为空指针

    shared_ptr和unique_ptr都支持的操作

    unique_ptr<T> up

    shared_ptr<T> sp

    空智能指针,指向类型为T的对象

    p

    作为一个条件判断,指向一个对象则为true

    *p

    解引用,获得指向的对象

    p->item

    等价于(*p).item

    p.get()

    返回p中保存的指针

    swap(p, q)

    p.swap(q)

    交换p和q中的指针

    shared_ptr独有的操作

    make_shared<T>(args)

    返回一个shared_ptr,使用args初始化T的对象

    shared_ptr<T> p(q)

    p是q的拷贝,指向同一个对象,q中计数器递增

    p=q

    递减p中引用计数,递增q中引用计数

    p.unique()

    如果p.use_count()为1,返回true

    p.use_count()

    返回p共享对象的智能指针的数量,很慢,用于调试

    使用动态内存的三种原因

    1. 程序不知道需要使用多少对象
    2. 程序不知道所需对象的准确类型
    3. 程序需要在多个对象间共享数据

    12.1.2直接管理内存

    int *ptr = new int; //默认初始化,值未定义
    int *ptr1 = new int();//值初始化为0
    int *ptr2 = new int(1024); 
    const int *ptr3 = new const int(1024);
    int *ptr4 = new (nothrow) int(1024);//分配失败,不抛出bad_alloc异常,而是返回空指针
    string *str = new string; //默认初始化为空string
    string *str1 = new string();//值初始化为空string
    string *str2 = new string("string");
    vector<int> *pv = new vector<int>{ 1, 2, 3, 4, 5 };
    auto p = new auto("123");//为const char**
    auto p = new auto(string("123"));//为string*
    
    int i, *pi1 = &i, *pi2 = nullptr;
    double *pd = new double(33), *pd2 = pd;
    delete i;  // 错误,i不是指针
    delete pi1; // 未定义,pil是一个局部变量
    delete pd;  // 成功
    delete pd2; // 未定义,pd2已经被释放
    delete pi2; // 成功,释放了一个为空的指针

    释放内存之后,指针变成了悬空指针(dangling pointer),通常仍然指向原来的内存地址,如果之后再次delete,会破坏自由空间内存,通常需要重新赋予nullptr。

    12.1.3结合使用shared_ptr和new

    shared_ptr<int> p2 = new int(42);// 错误int*不能隐式转换成智能指针
    shared_ptr<int> p2(new int(42));// 正确,因为构造函数是explicit,上边才不成立
    int* q = new int(10);
    shared_ptr<int> p(q, [](int* p) {cout << *p; delete p; });// 自定义释放内存的方法

    不建议结合使用

    其他操作

    shared_ptr<int> p(new int(9)); 
    int *pi = p.get();// 得到内置指针
    if (!p.unique())//不是唯一引用
        p.reset(new int(*p + 1));//改变p的指向,不影响其他引用的值
    *p = *p + 1;//唯一引用,直接改变也不影响其他的了

    12.1.4智能指针与.Net using

    void f(destination &d)
    {
        connection c = connect(&d);
        //保证在程序结束后释放c
        shared_ptr<connection> p(&c, [](auto c) {delete c; });
        ...
    }

    12.1.5独占智能指针unique_ptr

    unique_ptr不能进行赋值、拷贝操作

    unique_ptr<int> u;
    u = nullptr;//释放u的对象,并置空
    u.release();//释放u的对象控制,并返回内置指针,置空u
    u.reset();//释放u的对象
    u.reset(q);//指向q,释放u的对象

    可以拷贝和返回一个将要被销毁的unique_ptr例如参数返回时的拷贝,这其实是一种特殊的拷贝(13.6.2)。

    自定义删除器需要在定义时指明类型,这与shared_ptr作为参数不同。

    unique_ptr<int, decltype(process)*> u(new int(10), process);

    12.1.6弱智能指针weak_ptr

    weak_ptr将会绑定到一个shared_ptr,它不会改变shared_ptr的引用计数。

    弱智能指针需要用shared_ptr对象初始化。

    shared_ptr<int> u1(new int(50));
    weak_ptr<int> w = u1;
    w.reset();// 置空w
    w.use_count();//共享shared_ptr的数量
    w.expired();//user_count为0,返回true,否则为false
    w.lock();//返回对应的一个shared_ptr对象,如果expired为true,则返回的是空的对象
    if (shared_ptr<int> u = w.lock())//可以判断并得到shared_ptr

    12.2动态数组

    最好使用vector、string等其他标准库中的容器,这些标准库可以使用默认版本的拷贝、赋值和析构操作,而使用动态数组,就需要自己考虑了。

    12.2.1数组的new

    int *pia = new int[10];//10个未初始化
    int *pia1 = new int[10]();//10个值初始化为0
    int *pia2 = new int[10]{ 1,2,3 };//前三个为1,2,3,其他的为0
    1. 需要注意的是,分配的内存空间并不是数组类型空间,而仅仅是内存空间,并且返回一个首地址。
    2. 使用new分配的对象,执行默认初始化。

    释放时需要用到

    delete[] pia;

    对于释放时delete中如何知道内存中的大小,一般的编译器是通过在分配的动态数组前记录分配的内存的大小,然后释放的时候读取记录进行释放。

    使用智能指针管理动态数组

    unique_ptr<int[]> u(new int[10]);
    cout << u[10] << endl;
    u.release();//可以自动调用delete []
    
    shared_ptr<int> sp(new int[10], [](int*p) {delete[] p; });//需要自定义销毁函数
    sp.reset();//使用自定义销毁函数

    shared_ptr不直接支持动态数组管理,所以也不支持下标运算和指针的算术运算,需要使用时,必须使用get获取内置指针。

    allocator<T> a

    定义一个为T类型对象分配内存的allocator对象

    a.allocate(n)

    为n个T类型对象分配内存

    a.deallocate(p, n)

    收回为n个T类型对象分配的内存

    a.construct(p, args)

    在p指向的位置构造T对象(需要一个一个构造)

    a.destroy(p)

    销毁p指向位置的T对象(需要一个一个销毁)

    int count = 10;
    allocator<string> a;
    //分配内存
    string* p = a.allocate(count);
    for (int i = 0; i < count; i++)
        a.construct(p + i);//构造对象
    for (int i = 0; i < count; i++)
        a.destroy(p + i);//销毁对象
    //收回内存
    a.deallocate(p, count);

    uninitialized_copy(b,e,b2)

    从迭代器b到e的范围中的对象,内拷贝到b2内存中

    uninitialized_copy_n(b,n,b2)

    从迭代器b开始的n个元素拷贝到b2内存中

    uninitialized_fill(b,e,t)

    在b到e的范围中创建t的拷贝

    uninitialized_fill_n(b,n,t)

    在b开始的n个元素内存中,创建t的拷贝

  • 相关阅读:
    out/host/linuxx86/obj/EXECUTABLES/aapt_intermediates/aapt 64 32 操作系统
    linux 查看路由器 电脑主机 端口号 占用
    linux proc进程 pid stat statm status id 目录 解析 内存使用
    linux vim 设置大全详解
    ubuntu subclipse svn no libsvnjavahl1 in java.library.path no svnjavahl1 in java.library.path no s
    win7 安装 ubuntu 双系统 详解 easybcd 工具 不能进入 ubuntu 界面
    Atitit.json xml 序列化循环引用解决方案json
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.跨语言  文件夹与文件的io操作集合  草案
    Atitit.atijson 类库的新特性设计与实现 v3 q31
  • 原文地址:https://www.cnblogs.com/qiusuo/p/5005727.html
Copyright © 2011-2022 走看看