• 【足迹C++primer】40、动态数组


    动态数组
    C++语言定义了第二种new表达式语法。能够分配并初始化一个对象数组。标准库中包括
    一个名为allocator的类。同意我们将分配和初始化分离。


    12.2.1 new和数组

    void fun1()
    {
       int *pia=new int[2]; //pia指向第一个int
       //方括号里的大小必须是整型,但不必是常量
       typedef int arrT[42];    //arrT表示42个int的数组类型
       int *p=new arrT;         //分配一个42个int的数组;p指向第一个int
       //实际上,编译的时候还是这种
       int *p1=new int[42];
    }
    

    分配一个数组会得到一个元素类型的指针

    因为分配的内存并非一个数组类型。因此不能对动态数组调用begin或end
    也不能使用范围for语句来处理动态数组中的元素

    初始化动态分配对象的数组

        int *pia=new int[10];           //10个未初始化的int
        int *pia2=new int[10]();        //10个值初始化为0的int
        string *psa=new string[10];     //10个空string
        string *psa2=new string[10]();  //10个空string
        //新标准中。我们还能够这样写
        //10个int分别用列表中相应的值进行初始化
        int *pia3=new int[10]{0,1,2,3,4,5,6,7,8,9};
        //10个string类型的前面4个用给的值进行初始化。后面的进行值初始化
        string *psa3=new string[10]{"a","an","the",string(3,'x')};
    

    动态分配一个空数组是合法的

        size_t n=10,n2=0;
        int *p=new int[n];  //分配数组保存元素
        for(int* q=p ; q != p ; ++q)
        {
            /* 处理数组 */
        }

    若n为0,new会分配0个对象。

    for循环中的条件会失败(p等于q+n,由于n为0)。

    因此,循环体不会被运行

    释放动态数组

        int *p=new int;
        int *pa=new int[110];
         //为了释放动态数组,我们使用一种特殊形式的delete——在指针前加上一方括号对
         delete p;  //p必须指向一个动态分配的对象或为空
         delete [] pa;  //pa必须指向一个动态分配的数组或为空
    
         typedef int arrT[42];      //arrT是42个int的数组的类型别名
         int *p1=new arrT;           //分配一个42个int的数组;p指向第一个元素
         delete [] p1;               //方括号是必须的,由于我们当初分配的是一个动态数组
    

    无论外面怎样,p指向的是一个对象数组的首元素,而不是一个类型为arrT的单一对象。


    因此释放的时候必须加上方括号

    智能指针和动态数组

        //up指向一个包括10个未初始化的int的数组
        unique_ptr<int[]> up(new int[10]);
        up.release();       //自己主动用delete[]销毁其指针
        //当一个unique_ptr指向一个动态数组的时候我们能够用下标訪问数组中的元素
        for(size_t i=0 ; i != 10 ; ++i)
            up[i]=i;        //为每一个元素赋予一个新值
    

        和unique_ptr不同,shared_ptr不直接支持管理动态数组。

    假设希望shared_ptr管理一个动态
        数组。那么就必须自己提供自定义的删除器

        //为了适应shared_ptr,必须提供自定义的删除器
        shared_ptr<int> sp(new int[10], [](int *p){delete [] p;});
        sp.reset(); //使用我们提供的lambda释放数组,它使用delete[]
        //shared_ptr没有定义下标运算,也不支持下标运算
        for(size_t i=0 ; i != 10 ; ++i)
            *(sp.get()+i)=i;        //使用get获取一个内置指针

    12.23

    /**
    12.23
    编写一个程序,链接两个字符串字面常量,将结果保存在一个动态分配的char数组中
    重写这个程序。连接两个标准库string对象
    */
    void fun6()
    {
        string s1="cutter",s2="_point";
        unique_ptr<char[]> upc(new char[20]);
    
        for(size_t i=0 ; i != s1.size()+s2.size() ; ++i)
        {
            if(i < s1.size())
                upc[i]=s1[i];
            else
                upc[i]=s2[i-s1.size()];
        }
    
        for(int j=0 ; j != 20 ; ++j)
            cout<<upc[j];
    
    
        upc.release();      //自己主动用delete[]销毁其指针
    
    }

    12.2.2allocator类

    普通情况下。将内存分配和对象构造结合在一起可能会导致不必要的浪费
        int n;
        string *const p=new string[n];      //构造n个空string
        string s;
        string *q=p;        //q指向第一个string
        while(cin>>s && q != p+n)
            *q++=s;         //赋予*q一个新值
        const size_t size=q-p;      //记住我们读取了多少个string
        //使用数组
        delete [] p;        //p指向一个数组;记得用delete[]来释放

    可是。我们可能不须要n个string,少量string可能就足够了。

    allocator类

        int n;
        allocator<string> alloc;        //可分配string的allocator对象
        auto const p=alloc.allocate(n); //分配n各未初始化的string
        /*
        allocator分配微构造的内存
        */
        auto q=p;     //这里q指向和p一样
        alloc.construct(q++);   //*q为空字符串
        alloc.construct(q++, 10, 'c');  //*q为cccccccccc
        alloc.construct(q++, "hi");     //*q为hi!
        //q指向最后构造的元素之后的位置
        cout<<*p<<endl; //正确;使用string输出运算符
    //    cout<<*q<<endl; //灾难:q指向微构造的内存
    
        while(q != p)
            alloc.destroy(--q);     //释放我们真正构造的string
    

    所有代码展示

    /**
    * 功能:动态数组
    * 时间:2014年7月9日10:05:01
    * 作者:cutter_point
    */
    
    #include<iostream>
    #include<memory>
    #include<string>
    #include<vector>
    
    using namespace std;
    
    /**
    C++语言定义了第二种new表达式语法,能够分配并初始化一个对象数组。

    标准库中包括 一个名为allocator的类,同意我们将分配和初始化分离。 */ /** 12.2.1 new和数组 */ void fun1() { int *pia=new int[2]; //pia指向第一个int //方括号里的大小必须是整型。但不必是常量 typedef int arrT[42]; //arrT表示42个int的数组类型 int *p=new arrT; //分配一个42个int的数组。p指向第一个int //实际上,编译的时候还是这种 int *p1=new int[42]; } /** 分配一个数组会得到一个元素类型的指针 */ /* 由于分配的内存并非一个数组类型,因此不能对动态数组调用begin或end 也不能使用范围for语句来处理动态数组中的元素 */ /** 初始化动态分配对象的数组 */ void fun2() { int *pia=new int[10]; //10个未初始化的int int *pia2=new int[10](); //10个值初始化为0的int string *psa=new string[10]; //10个空string string *psa2=new string[10](); //10个空string //新标准中。我们还能够这样写 //10个int分别用列表中相应的值进行初始化 int *pia3=new int[10]{0,1,2,3,4,5,6,7,8,9}; //10个string类型的前面4个用给的值进行初始化,后面的进行值初始化 string *psa3=new string[10]{"a","an","the",string(3,'x')}; } /** 动态分配一个空数组是合法的 */ void fun3() { size_t n=10,n2=0; int *p=new int[n]; //分配数组保存元素 for(int* q=p ; q != p ; ++q) { /* 处理数组 */ } /* 若n为0。new会分配0个对象。

    for循环中的条件会失败(p等于q+n,由于n为0)。

    因此,循环体不会被运行 */ } /** 释放动态数组 */ void fun4() { int *p=new int; int *pa=new int[110]; //为了释放动态数组。我们使用一种特殊形式的delete——在指针前加上一方括号对 delete p; //p必须指向一个动态分配的对象或为空 delete [] pa; //pa必须指向一个动态分配的数组或为空 typedef int arrT[42]; //arrT是42个int的数组的类型别名 int *p1=new arrT; //分配一个42个int的数组;p指向第一个元素 delete [] p1; //方括号是必须的,由于我们当初分配的是一个动态数组 /* 无论外面怎样,p指向的是一个对象数组的首元素。而不是一个类型为arrT的单一对象。 因此释放的时候必须加上方括号 */ } /** 智能指针和动态数组 */ void fun5() { //up指向一个包括10个未初始化的int的数组 unique_ptr<int[]> up(new int[10]); up.release(); //自己主动用delete[]销毁其指针 //当一个unique_ptr指向一个动态数组的时候我们能够用下标訪问数组中的元素 for(size_t i=0 ; i != 10 ; ++i) up[i]=i; //为每一个元素赋予一个新值 /* 和unique_ptr不同,shared_ptr不直接支持管理动态数组。

    假设希望shared_ptr管理一个动态 数组,那么就必须自己提供自定义的删除器 */ //为了适应shared_ptr,必须提供自定义的删除器 shared_ptr<int> sp(new int[10], [](int *p){delete [] p;}); sp.reset(); //使用我们提供的lambda释放数组,它使用delete[] //shared_ptr没有定义下标运算,也不支持下标运算 for(size_t i=0 ; i != 10 ; ++i) *(sp.get()+i)=i; //使用get获取一个内置指针 } /** 12.23 编写一个程序,链接两个字符串字面常量,将结果保存在一个动态分配的char数组中 重写这个程序,连接两个标准库string对象 */ void fun6() { string s1="cutter",s2="_point"; unique_ptr<char[]> upc(new char[20]); for(size_t i=0 ; i != s1.size()+s2.size() ; ++i) { if(i < s1.size()) upc[i]=s1[i]; else upc[i]=s2[i-s1.size()]; } for(int j=0 ; j != 20 ; ++j) cout<<upc[j]; upc.release(); //自己主动用delete[]销毁其指针 } /** allocator类 */ /* 普通情况下,将内存分配和对象构造结合在一起可能会导致不必要的浪费 */ void fun7() { int n; string *const p=new string[n]; //构造n个空string string s; string *q=p; //q指向第一个string while(cin>>s && q != p+n) *q++=s; //赋予*q一个新值 const size_t size=q-p; //记住我们读取了多少个string //使用数组 delete [] p; //p指向一个数组;记得用delete[]来释放 /* 可是。我们可能不须要n个string。少量string可能就足够了。

    */ } /* allocator类 */ void fun8() { int n; allocator<string> alloc; //可分配string的allocator对象 auto const p=alloc.allocate(n); //分配n各未初始化的string /* allocator分配微构造的内存 */ auto q=p; //这里q指向和p一样 alloc.construct(q++); //*q为空字符串 alloc.construct(q++, 10, 'c'); //*q为cccccccccc alloc.construct(q++, "hi"); //*q为hi! //q指向最后构造的元素之后的位置 cout<<*p<<endl; //正确;使用string输出运算符 // cout<<*q<<endl; //灾难:q指向微构造的内存 while(q != p) alloc.destroy(--q); //释放我们真正构造的string } int main() { fun6(); return 0; }



    PS:花了一早上,就搞了这么点东西,尽管中途歇息了一会。而且还玩了半个多小时的游戏大笑,可是哥还是把这玩意所有搞完了,哈哈搞完了就能够好好玩一玩啦!!

  • 相关阅读:
    「题解」:07.16NOIP模拟T1:礼物
    「题解」:07.16NOIP模拟T2:通讯
    「题解」:图论专题总结
    07.07NOIP模拟赛
    [复习]平衡树splay
    「题解」:[组合数学][DP]:地精部落
    「题解」:[组合数学]:Perm 排列计数
    「题解」:[组合数学]:排队
    dp 杂题
    插头 dp 总结
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5157024.html
Copyright © 2020-2023  润新知