欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c++ vector 使用注意事项

程序员文章站 2022-03-20 20:24:45
1. 初始化 c++ 11以后新增了大括号{}的初始化方式,需要注意与()的区别,如: std::vector vecTest1(5); //初始化5个元素,每个都是0 std::vector vecTest2{ 5 }; //初始化1个元素,值是5 2. 添加元素:push_b ......

1. 初始化

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

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

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

    c++ vector 使用注意事项

 

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,这个时候直接添加元素到尾部,内存明显是不够的,此时会重新在别处分配一块大小足够

     有时候也有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;

  c++ vector 使用注意事项

       

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);

     c++ vector 使用注意事项

 

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

c++ vector 使用注意事项