容器大小的改变以及容器操作可能使迭代器失效、vector对象的容量变化

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 1 改变容器的大小 我们可以使用resize来增加或缩小容器,与往常一样,array不支持resize。如果当前大小大于所要求的大小,容器后面的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部:  list ilist(10,42);   //10个int:每个的值都是42 ilist.

1 改变容器的大小

我们可以使用resize来增加或缩小容器,与往常一样,array不支持resize。如果当前大小大于所要求的大小,容器后面的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部:

 list<int> ilist(10,42);   //10个int:每个的值都是42

ilist.resize(15);   //将5个值为0的元素添加到ilist的末尾

ilist.resize(25,-1);  //将10个值为-1的元素添加到ilist的末尾

ilist.resize(5);    //从ilist末尾删除20个元素

resize操作接受一个可选的元素值参数,用来初始化添加到容器中的元素。如果调用者未提供此参数,新元素进行值初始化。如果容器保存的是类类型,且resize向容器添加新元素,则我们必须提供初始值,或者元素类型必须提供一个默认构造函数。

顺序容器大小操作

resize不适用array

c.resize(n)      调整c的大小为n个元素。若n<c.size(),则多出的元素被丢弃。若必须添加新元素,对新元素进行值初始化

c.resize(n,t)      调整c的大小为n个元素。任何新添加的元素都初始化为值t

 

注意:如果resize缩小容器,则指向被删除元素的迭代器、引用和指针都会失效;对vector、string或deque进行resize可能导致迭代器、指针和引用失效

 

容器操作可能使迭代器失效

向容器中添加元素和从容器中删除元素的操作可能会使指向容器的指针、引用或迭代器失效。一个失效的指针、引用或迭代器将不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误,很可能引起与使用未初始化指针一样的问题

向容器添加元素后:

  • 如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效。如果存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用将会失效。
  • 对于deque。插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效
  • 对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍然有效。

当我们从一个容器中删除元素后,指向被删除元素的迭代器、指针和引用会失效。当我们删除一个元素后:

  • 对于list和forward_list,指向容器其他位置的迭代器、指针和引用仍然有效
  • 对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、引用或指针也会失效。如果是删除deque的尾元素,则尾后迭代器也会失效,但其他迭代器、引用和指针不受影响;如果是删除首元素,这些也不会受影响。
  • 对于vector和string,指向被删除元素之前元素的迭代器、引用和指针仍有效。注意:当我们删除元素时,尾后迭代器总是会失效。

 

编写改变容器的循环程序

添加/删除vector、string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题。程序必须保证每个循环步中都更新迭代器、引用和指针。如果循环中调用的是insert或erase,那么更新迭代器很容易。这些操作都返回迭代器,我们可以用来更新:

//傻瓜循环,删除偶数元素,复制每个奇数元素
vector<int> vi={0,1,2,3,4,5,6,7,8,9};
auto iter=vi.begin();  //调用begin而不是cbegin,因为我们要改变vi
while(iter!=vi.end()) 
{
    if(*iter%2){
        iter=vi.insert(iter,*iter);//复制当前元素
        iter+=2;   //向前移动迭代器,跳过当前元素以及插入到它之前的元素
    }
    else
        iter=vi.erase(iter);  //删除偶数元素
    //不应向前移动迭代器,iter指向我们删除的元素之后的元素
}

此程序删除vector中的偶数元素,并复制每个奇数元素。我们在调用insert和erase后都更新迭代器,因为两者都会使迭代器失效。

 

不要保存end返回的迭代器

当我们添加/删除vector或string的元素后,或在deque中首元素之外任何位置添加/删除元素后,用来end返回的迭代器总是会失效。因此,添加或删除元素的循环程序必须反复调用end,而不能在循环之前保存end返回的迭代器,一直当作容器末尾使用。

 

vector对象时如何增长的

为了支持随机访问,vector将元素连续存储——每个元素紧挨着前一个元素存储。通常情况下,我们不必关心一个标准库类型是如何实现的,而只需关心它如何使用。然而,对于vector和string,其部分实现渗透到了接口中。

假定容器中元素是连续存储的,其容器的大小是可变的,考虑向vector和string中添加元素会发生什么;如果没有空间容纳新元素,容器不可能简单地将它添加到内存中其他位置——因为元素必须连续存储。容器必须分配新的内存空间来保存已有元素和新元素,将已有元素从旧位置移动到新空间中,然后添加新元素,释放就存储空间。如果我们每添加一个新元素,vector就执行一次这样的内存分配和释放操作,性能会慢到不可接受。

 

管理容器的成员函数

vector和string类型提供了一些成员函数,允许我们与它的实现中内存分配部分互动。capacity操作告诉我们容器在不扩张内存空间的情况下可以容纳多少个元素。reserve操作允许我们通知容器它应该准备保存多少个元素。

容器大小管理操作

shrink_to_fit只适用于vector、string和deque

capacity和reserve只适用于vector和string

c.shrink_to_fit()       请将capacity减少为size相同大小

c.capacity()      不重新分配内存空间的话,c可以保存多少元素

c.reserve(n)       分配至少能容纳n个元素的内存空间

reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间

只有当需要的内存空间超过当前容量时,reserve调用才会改变vector的容量。如果要求大小大于当前容量,reserve至少分配与要求一样大的内存空间(可能更大)。

如果需求大小小于等于当前空间,reserve什么也不做。特别是,当需求大小小于当前容量时,容器不会退回内存空间。因此,在调用reserve之后,capacity将会大于等于传递给reserve的参数。

这样,调用reserve永远也不会减少容器占用的内存空间。类似的,resize成员函数只改变容器中元素的数目,而不是容器的容量我们同样不能使用resize来减少容器预留的内存空间

在新标准中,我们可以调用shrink_to_fit来要求deque、vector或string退回不需要的内存空间。此函数指出我们不再需要任何多余的内存空间。但是,具体的实现可以选择忽略此请求。也就是说,调用shrink_to_fit也并不保证一定退回内存空间。

 

capacity和size

容器size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。

 

相关文章
|
4月前
|
存储 C++ 容器
如何将没有复制或移动构造函数的对象放入vector容器
如何将没有复制或移动构造函数的对象放入vector容器
46 0
|
6月前
|
存储 算法 编译器
8.STL中Vector容器的常见操作(附习题)
8.STL中Vector容器的常见操作(附习题)
|
5月前
|
缓存 Serverless 容器
函数计算操作报错合集之在创建容器时遇到报错,如何处理
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
|
6月前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
96 10
|
6月前
|
C++ 容器
C++之评委打分案例(vector与deque容器练习)
C++之评委打分案例(vector与deque容器练习)
|
6月前
|
存储 算法 C++
C++一分钟之-容器概览:vector, list, deque
【6月更文挑战第21天】STL中的`vector`是动态数组,适合随机访问,但插入删除非末尾元素较慢;`list`是双向链表,插入删除快但随机访问效率低;`deque`结合两者优点,支持快速双端操作。选择容器要考虑操作频率、内存占用和性能需求。注意预分配容量以减少`vector`的内存重分配,使用迭代器而非索引操作`list`,并利用`deque`的两端优势。理解容器内部机制和应用场景是优化C++程序的关键。
76 5
|
6月前
|
存储 算法 C++
【C++/STL】:vector容器的基本使用
【C++/STL】:vector容器的基本使用
47 1
|
5月前
|
API 开发工具 数据安全/隐私保护
阿里云云效操作报错合集之流水线镜像已经生成,但容器没有出现,是什么导致的
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
5月前
|
敏捷开发 Kubernetes 测试技术
阿里云云效产品使用合集之流水线创建时,不想选择节点和容器,该如何操作
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
5月前
|
存储 安全 C++