1.【STL源码剖析】总结笔记(3):vector初识
2.size_tçä»ç»
3.STL源码学习(3)- vector详解
4.用memcpy函数拷贝vector
5.Java集合-Vector介绍、源码扩容机制、源码源码分析
【STL源码剖析】总结笔记(3):vector初识
vector是c++中常用且重要的容器之一。相较于固定大小的源码array,vector拥有动态分配内存的源码特性,允许它在使用过程中随着元素的源码lapack源码增删而自行调整大小。这种动态性使得vector在处理不可预知数据量时更为便捷。源码
内部结构上,源码vector使用了数组作为存储基础,源码并通过start,源码 finish和end of storage三个迭代器进行访问和管理空间。其中,源码start和finish分别指向可用空间的源码首端和尾端,end of storage则指向内存块的源码末尾。在vector大小为字节(位系统下,源码一个指针占4字节)的源码情况下,其大小为3。因此,vector可以灵活地通过迭代器定位数据的大小与位置。
内存管理机制是vector的精华之一。当空间耗尽时,vector会自动扩展为二倍的内存容量,以容纳新增元素。此过程涉及创建新空间,百乐平台源码复制原有数据,然后释放旧空间,确保资源的有效利用。
vector提供了丰富的迭代器,遵循随机访问的行为,允许直接获取和修改数据,增强操作的效率。这些迭代器简化了对数据结构的遍历与修改操作。
在添加与删除数据时,vector提供了pop_back(), erase, insert等高效方法。例如,pop_back()简单地删除尾部元素,erase允许清除一个范围内的数据,并通过复制来维持数据的连续性。insert操作根据具体需求进行数据的插入与调整,确保结构的完整性与数据的正确性。
综上,vector以其灵活的内存管理和高效的数据操作,成为学习STL和掌握容器结构的理想选择。其清晰的内部机制和丰富的功能特性,为程序设计提供了强大的支持。
size_tçä»ç»
size_t ç±»åå®ä¹å¨cstddef头æ件ä¸ï¼è¯¥æ件æ¯Cæ ååºç头æ件stddef.hçC++çãå®æ¯ä¸ä¸ªä¸æºå¨ç¸å ³çunsignedç±»åï¼å ¶å¤§å°è¶³ä»¥ä¿è¯åå¨å åä¸å¯¹è±¡ç大å°ãä¾å¦ï¼bitsetçsizeæä½è¿åbitset对象ä¸äºè¿å¶ä½ä¸ç个æ°ï¼è¿åå¼ç±»åæ¯size_tãä¾å¦ï¼å¨ç¨ä¸æ 访é®å ç´ æ¶ï¼vector使ç¨vector::size_typeä½ä¸ºä¸æ ç±»åï¼èæ°ç»ä¸æ çæ£ç¡®ç±»ååæ¯size_tãvector使ç¨çä¸æ å®é ä¹æ¯size_tï¼æºç æ¯typedef size_t size_typeãSTL源码学习(3)- vector详解
STL源码学习(3)- vector详解
vector的单页公告源码迭代器与数据类型:vector内部的连续存储结构使得任何类型的数据指针都可以作为其迭代器。通过迭代器,可以执行诸如指针操作,如访问元素值。 vector定义了两个迭代器start和finish,分别指向元素的起始和终止地址,同时还有一个end_of_storage标记空间的结束位置。vector的容量保证大于等于已分配元素空间,提供了获取空间大小的函数,如front和back的值以引用返回,更高效。 空间配置原理:STL中的vector使用SGI STL容器的二级空间配置器。vector头部包含配置信息,如data_allocator作为空间配置器的别名。简单配置器(simple_alloc)是封装了高级和低级配置器调用的抽象类。 构造函数与内存管理:vector通过空间配置器创建元素。构造函数允许预分配并初始化元素,fill_initialize用于调整空间范围,allocate_and_fill则分配空间并填充。这个过程涉及data_allocator的allocate函数,分配空间并返回起始地址。 vector析构时,调用deallocate函数释放空间。共享扫码源码pop_back和erase方法会移除元素并销毁相应空间,clear则清除全部元素。insert操作复杂,根据元素数量和容器状态可能需要扩容。 插入与扩展操作:push_back在末尾插入元素,如果空间不足,可能需要扩容。insert接受三个参数,根据情况处理插入操作,可能抛出异常并销毁部分元素。用memcpy函数拷贝vector
定义了两个vector,vector里面存的是类,是否可以直接使用memcpy去复制vector?这个问题涉及C库函数strcpy、memcpy和memmove。让我们先了解这三种函数,然后再解答这个问题。
1. strcpy, memcpy以及memmove
strcpy, memcpy, memmove都是C库函数,它们的原型如下:
strcpy 不需要传入复制的字节数,而memcpy和memmove需要,这是因为memcpy和memmove需要明确知道要复制的字节数。
2. 用memcpy函数拷贝vector
分步骤来考虑这个问题。
2.1 初探
我们先考虑vector存放内置类型的取设备id源码情况。不同于数组,vector对象在使用时不会转换成指针,因此,需要使用取地址符&来得到vector对象的地址。
执行上述代码后,我们发现test1中元素的地址可以正常输出。
然而,当程序退出时,引发"读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突"的异常,这是为什么呢?我们可以发现,test1中元素的地址和test中的是相同的!那么,我们可以做出如下猜测:
当程序退出时,后声明的test1先被释放。轮到test调用其析构函数释放内存时,其中的元素在test1释放时就已经被释放,再尝试访问这些元素进行内存释放会引发“访问冲突”的异常。
那应该怎么做呢?
我们先给test1分配空间,并默认初始化:
然后,将复制语句改成
此时程序正常运行并正常退出。我们用&test[0], &test1[0]真正地取到了test, test1的首元素的地址,函数按照顺序将test中的元素复制到test1中。
注意:不能写成 的形式,因为sizeof(test)得到的是vector的大小,这是一个固定值,和其中存储的值的数量、类型(除了bool)无关。和我们实际想要复制的长度不同,会引发各种各样的错误。
2.2 进一步探索
考虑vector存放类类型的情况。定义一个MyClass类,执行下列语句,确实先析构了test1中的元素,等到test调用其析构函数时,访问冲突异常。按照第一章中的方式进行修改,变量正常析构,程序正常退出。
注意:
2.3 更进一步
之前提到,STL容器占的字节数和储存的数据的数目和类型(除了bool)无关,是一个固定值。用vector举例,网上很多回答都是说vector中有三个迭代器变量:start, finish, end_of_storage。这三个迭代器的类型是type* 类型指针。因此vector的大小是固定的,在位机上是(debug版本),在位机上是(debug版本)。
并且有说vector::begin()函数返回start;vector::end()函数返回finish... 不知道是不是版本或者编译器的问题,至少在我在vs中,sizeof(vector)的结果有多种,尝试了一些常见的类型:
观察上述运行结果,除了bool很特殊之外,其他的似乎和上述说法吻合。然而,当我执行下列语句时:
得到的结果为:
只有当type不为bool且在release版本下才满足上述说法。
2.3.1 bool类型的特殊之处
bool类型的变量占1个字节,但是bool类型只有两个取值false和true. 因此,为了提高效率,在vector中,bool变量是按位储存的。为了实现这一优化,vector除了有一般vector的成员变量外,还有两个额外的成员变量:
在位机上,这两个变量都占8个字节,因此在debug版本下,vector比vector多占个字节。release版本下可能只有其中一个变量,具体是哪个我也还不清楚。
一般的vector对象在使用[]运算符时, 返回一个类型为OtherType&的左值;而vector对象访问一个代理引用(proxy reference)而非真正的引用(true reference),并返回一个类型为_Vb_reference<_Wrap_alloc > >的右值,因此不能用该返回值初始化一个bool&:
虽然vb[0]不是一个左值,但是仍然可以通过修改它的值来修改vb:
2.3.2 一般的vector
一种说法是:一般的vector只有一个迭代器:_Compressed_pair<_Alty, _Scary_val> _Mypair,它在位机器上占个字节,begin(),end()函数都返回它。因此debuge版本下sizeof(vector::begin())的值为. 这种说法仅供参考。
参考链接:
STL源码剖析-vector
谈vector的特殊性——为什么它不是STL容器
c语言中memcpy是字节大小, 使用memcpy函数时要注意拷贝数据的长度
C++之strcpy、memcpy、memmove比较
Java集合-Vector介绍、扩容机制、源码分析
Java集合框架中的Vector类是一种古老的线程安全的数组列表,本文将简要介绍Vector,深入剖析其扩容机制,以及源码层面的解析。
首先,我们来看创建Vector的方式。Vector提供了无参构造器和带初始容量和扩容增量的构造器。无参构造会设置initialCapacity为,capacityIncrement默认为数组长度的两倍。例如,调用this()或this(initialCapacity, 0),实际上是为元素数据(elementData)分配了初始容量,但后续扩容会根据capacityIncrement值调整,如未指定则每次翻倍。
当向Vector添加元素时,会触发add方法。例如,添加第一个元素1,若数组已满,会调用ensureCapacityHelper(elementCount + 1),确保空间。此处,由于初始容量为,添加1后不需要扩容,元素直接添加到0索引。后续添加时,由于需要个位置,会进行扩容。判断条件是:新的容量减去最小需求小于0时,才会进行扩容,通常是将容量扩大为当前容量的两倍或直接扩容到满足需求的最小值。
总的来说,Vector的扩容机制是动态的,确保在元素数量增长时,内存空间能相应扩展。源码中,add方法、ensureCapacityHelper函数和grow方法共同实现了这一机制,保证了Vector在高并发环境下的线程安全。通过理解这些细节,我们可以更好地运用Vector并优化程序性能。