• c++ vector 使用注意事项


    1. 初始化

           c++ 11以后新增了大括号{}的初始化方式,需要注意与()的区别,如:

             std::vector<int> vecTest1(5);         //初始化5个元素,每个都是0

             std::vector<int> vecTest2{ 5 };       //初始化1个元素,值是5

        

    2.  添加元素:push_back

           通过push_back添加新的元素进入vector后,vector的内存有时候会发生变化,这取决于size和capacity大小,当然这些都是系统来处理的,详细可以参考stl源码

            当size<capacity的时候,直接加到末尾,不会变化

            当size==capacity的时候,会重新申请另外一块内存,然后copy过去加到尾部,这个时候就会有变化了。

            对于stl的容器,都有成员:

                     begin()  //起始位置 

                     end() //结束位置 

                     size() //当前大小 

             capacity() //当前容量,即已申请的内存大小

         vector是一段连续的内存空间,有三个标识内存的位置,start,end,finish, size=end-start, capacity=finish-start

         很多时候在使用vector的时候,会看到size=capacity,这个时候直接添加元素到尾部,内存明显是不够的,此时会重新在别处分配一块大小足够

    至于为什么要重新在new,而不是直接扩容添加在后面,一个是空间换时间,另一个更大的原有是连续的内存直接加在后面不一定够,重新new保证成功率

         有时候也有size<capacity, 这个时候就直接加在尾部了。

    std::cout << "vecNum push back init" << std::endl;
    vector<int> vecNum(5);
    std::cout << "vecNum addr: " << &vecNum << std::endl;
    for(auto i = 5; i < 10; i++)
    {
    	vecNum.push_back(i*10);
    	std::cout << "vecNum push_back(" << i << ")=" << i*10 << std::endl;
    
    	std::cout << "vecNum.size() = " << vecNum.size() << ",vecNum.capacity() = " << vecNum.capacity() << std::endl;
    	std::cout << "vecNum.begin() addr: " << &(*vecNum.begin()) << std::endl;
    }
    std::cout << "vecNum addr: " << &vecNum << std::endl;
    

      

           

    3. 关于earse和remove

         erase返回的是当前删除的元素的一下个位置的迭代器,所以需要注意的是遍历时候的++运算,这个与其它list,map差不多,

        需要注意的earse后内存并未真正的清空,仅仅是删除内容,真正的容量大小capacity并没有改变,需要通过swap来实现capacity的减小

         全部清空可以考虑:vector<int>().swap(vecNum);

    auto itor = vecNum.begin();
    for( ; itor != vecNum.end(); )
    {
        auto num = *itor;
        if(num == 60)
        {
            itor = vecNum.erase(itor);
            break;
        }
        else
        {
            itor++;
        }
    }

      std::cout << "after erase element 60:" << std::endl;
      printVector(vecNum);
      vector<int>(vecNum).swap(vecNum); //将vecNum的内存空洞清除
      printVector(vecNum);

         

          //remove只是通过迭代器的指针向前移动来删除,将不需要删除的元素往前移,因此需要删除的就都在尾部了

          //返回新的指向尾部需要删除的元素的迭代器

          因此还是得配合earse来使用,所以一般真要删除,建议直接遍历使用earse

    auto itor = remove_if(vecNum.begin(), vecNum.end(),[](int x)->bool{ return x == 20; });
    //or
    //auto itor = remove(vecNum.begin(), vecNum.end(),20);
            
    //通过erase删除
    vecNum.erase(itor, vecNum.end());


    4. 关于vector< bool>  -- 慎用

           出处: https://blog.csdn.net/DoronLee/article/details/78462208

           vector< bool> 并不是一个STL容器,不是一个STL容器,不是一个STL容器!

           首先vector< bool> 并不是一个通常意义上的vector容器,这个源自于历史遗留问题。 

    早在C++98的时候,就有vector< bool>这个类型了,但是因为当时为了考虑到节省空间的想法,所以vector< bool>里面不是一个Byte一个Byte储存的,它是一个bit一个bit储存的!

    因为C++没有直接去给一个bit来操作,

        所以用operator[]的时候, 正常容器返回的应该是一个对应元素的引用,

       但是对于vector< bool>实际上访问的是一个”proxy reference”而不是一个”true reference”,返回的是”std::vector< bool>:reference”类型的对象。

       因此,使用auto自动类型推导时会出现问题

    //vector<bool>慎用
    vector<bool> vecBool = { false, true, false };
    bool test1 = vecBool[0];   
    auto test2 = vecBool[1];

    test1 = true;    //test1的初始化它其实暗含了一个隐式的类型转换(直接对vecBool[0]赋值会修改vecBool中的值,但是对test1不会)
    test2 = false;   //test2它的类型并不是bool,而是一个vector< bool>中的一个内部类,而此时如果修改test2的值,vecBool中的值也会跟着修改
    auto index = 0;
    for (auto i : vecBool)
    {
        cout << "vecBool[" << index << "]" << i << std::endl;
        index++;
    }

         

  • 相关阅读:
    MAC OS下安装Minizip
    MAC OS下安装pkg_config
    计算机图形学-几何变换
    计算机图形学-图形系统
    Unix&Linux大学教程 读书笔记【1-3章】
    Mixins 混入选项操作
    watch监控,对比新值和旧值做出相应判断
    用.native修饰器来对外部组件进行构造器内部方法的调用以及用原生js获取构造器里的方法
    methods 方法选项
    computed 计算选项
  • 原文地址:https://www.cnblogs.com/leehm/p/10929756.html
Copyright © 2020-2023  润新知