2、vector的实现
vector其实就是动态数组。它的性质与数组基本一致。同样使用的是一片连续的内存空间。它与数组相比,其优点是灵活性较强,其空间大小可变。但是其效率没有数组高。这是因为受到了其空间配置器的影响。SGI-STL中,为了减少内存碎片,在空间配置方面有很多机制。创建一个vector时,需要分配填充内存池、填充free-list、分配内存等一系列操作。这使得它的效率稍微低了些。此外,当空间不足,需要扩充空间时,SGI-STL采用“三步走”的措施,即:分配新的空间——将原来数据拷贝过去——释放原来的空间。我们在使用时,应该尽量避免扩充vector的空间。还有一点应当注意,当写出如下代码的时候,虽然分配了10个元素的空间,当你紧接着再往容器中添加数据时,同样会扩充空间。也就是程序执行完成第2行代码时,其正在的元素个数已经变成了11,而不是原来的10。其具体原因请看源代码
vector<int> Vec(10);
Vec.push_back(10);
以下是我自己根据源代码,仿造的vector。
#ifndef CVECTOR_H_
#define CVECTOR_H_ #include "DefaultAllocTemplate.h"
#include "AllocatorInterface.h"
#include "comm.h"
#include <iterator.h>
#include <new.h>
#include <stdlib.h>
#include <unistd.h> template <class T, class Alloc = CDefaultAllocTemplate>
class CVector {
/*以下是Vector的迭代器类型*/
public:
typedef T ValueType;
typedef ValueType* Pointer;
typedef ValueType* Iterator;
typedef ValueType& Reference;
typedef size_t SizeType;
typedef ptrdiff_t DifferenceType;
protected: /*空间配置器*/
typedef AllocatorInterface<ValueType,Alloc>DataAllocator; /*目前正在使用的空间的头部*/
Iterator m_Start; /*目前正在使用空间的尾部*/
Iterator m_Finish; /*可用空间的尾部,它与m_Start决定了容器的最大容量*/
Iterator m_EndOfStorage; /*向Vetory中插入一个成员*/
void InsertAux(Iterator Pos, const T& x); /*销毁容器*/
void Deallocate()
{
if( != m_Start)
{
/*调用空间配置器接口中的函数销毁销毁容器*/
DataAllocator::Deallocate(m_Start, m_EndOfStorage - m_Start);
}
} /*创建容器,并为其分配存储空间。该函数可以获取uiNum个对象的内存空间,
*并将内存指针保存在m_Start中。以后的构造函数中,都会调用这个函数*/
void FillInitialize(SizeType uiNum, const T& Value)
{
m_Start = AllocateAndFill(uiNum, Value);
/*注意,这里会使得原来的你在创建vector的时候,无论你申请了多少个元素的空间,当你(即使是申请后马上)
*调用PushBack函数时,也会扩大原来的内存空间*/
m_Finish = m_Start + uiNum;
m_EndOfStorage = m_Finish;
} /*配置空间并填充内容*/
Iterator AllocateAndFill(SizeType uiNum, const T& Value)
{
Iterator Result=DataAllocator::Allocate(uiNum);
//调用全局函数为对象配置内存
uninitialized_fill_n(Result, uiNum, Value);
return Result;
} public:
/*获取容器起始位置*/
Iterator Begin()
{
return m_Start;
} /*获取容器中正在使用空间的尾部*/
Iterator End()
{
return m_Finish;
} /*返回容器中元素个数*/
SizeType Size()
{
return (SizeType)(m_Finish - m_Start);
} SizeType Capacity()
{
return (SizeType)(m_EndOfStorage - m_Start);
} /*判断容器是否为空*/
int Empty()
{
return m_Start == m_Finish;
} /*重载"[]"符号,让容器可以通过下标获取元素*/
Reference operator[](SizeType uiNum)
{
return *(m_Start + uiNum);
} /*无参构造函数,创建一个空的容器*/
CVector() : m_Start(), m_Finish(), m_EndOfStorage()
{
//这里面本身就不需要任何内容
} /*以下三个构造函数功能一样,都是创建一个可以容纳uiNum个对象的容器。并且会将Value中的数据拷贝uiNum个过去。
*只是其中的uiNum类型不一样,这里写三个是为了兼容不同的类型*/
CVector(SizeType uiNum, const T& Value)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间*/
FillInitialize(uiNum, Value);
} CVector(int uiNum, const T& Value)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间*/
FillInitialize(uiNum, Value);
} CVector(long uiNum, const T& Value)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间*/
FillInitialize(uiNum, Value);
} /*创建能容纳uiNum个对象的容器*/
explicit CVector(long uiNum)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间,其中的T()将会创建一个临时变量。但是为什么需要这样去创建呢??
*为了让该函数能够调用,所以创建一个临时对象*/
FillInitialize(uiNum, T());
} explicit CVector(int uiNum)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间,其中的T()将会创建一个临时变量。但是为什么需要这样去创建呢??
*为了让该函数能够调用,所以创建一个临时对象*/
FillInitialize(uiNum, T());
} explicit CVector(SizeType uiNum)
{
/*这三行是为了消除警告*/
m_Start = ;
m_Finish = ;
m_EndOfStorage = ; /*调用函数分配内存空间,其中的T()将会创建一个临时变量。但是为什么需要这样去创建呢??
*为了让该函数能够调用,所以创建一个临时对象*/
FillInitialize(uiNum, T());
} ~CVector()
{
/*一个对象的销毁分为两步完成:
*1、释放容器的内存空间
*2、销毁容器*/
destroy(m_Start, m_EndOfStorage);//释放容器占用的内存空间
Deallocate();//调用容器中的函数,销毁容器
} /*返回第一个元素*/
Reference Front()
{
return *(m_Start);
} /*返回最后一个元素*/
Reference Back()
{
return *(m_Finish - );
} /*向vector的尾部添加一个元素*/
void PushBack(const T& Element)
{
/*判断容器是否已经满了,如果没有满,则直接进行插入。如果满了,则需要调用InsertAux函数,
*为容器重新分配内存空间*/
if(m_Finish != m_EndOfStorage)
{
construct(m_Finish, Element);
++m_Finish;
}
else
{
InsertAux(End(), Element);
}
} /*将容器中最后一个元素取出来*/
void PopBack()
{
--m_Finish;
destory(m_Finish);
} /*清除指定位置的某个元素*/
Iterator Erase(Iterator Position)
{
if(Position + != End())
{
copy(Position + , m_Finish, Position);//将后面的数据向前移动
}
m_Finish--;
destroy(m_Finish);//调用全局函数,释放多余的空间
return Position;
} /*清除指定某区域中的元素*/
Iterator Erase(Iterator StartPosition, Iterator EndPosition)
{
if(EndPosition + != End())
{
copy(EndPosition + , m_Finish, StartPosition);//将后面的数据向前移动
}
m_Finish -= (StartPosition - EndPosition); //调整末尾指针
destroy(m_Finish, StartPosition - EndPosition);//调用全局函数,释放多余的空间
return StartPosition;
} /*重新为容器分配空间,其大小为uiNewSize,如果新的空间大于原来的空间,
*则新增加的空间将会以InitialValue作为初值进行初始化;如果新的空间
*小于原来的空间,将会把多余的数据清除掉*/
void Resize(SizeType uiNewSize, const T& InitialValue)
{
if(uiNewSize < Size())
{
Erase(Begin() + uiNewSize, End());//空间过小,清除元素
}
else
{
insert(End(), uiNewSize - Size(), End());
}
} /*重新为容器分配空间,其大小为uiNewSize。但是用户可以不进行初始化*/
void Resize(SizeType uiNewSize)
{
Resize(uiNewSize, T());
} /*清空容器中的元素*/
void Clear()
{
Erase(Begin(), End());
}
}; template <class T, class Alloc>
void CVector<T, Alloc>::InsertAux(Iterator Position, const T& Element)
{
if(m_Finish != m_EndOfStorage) //还有备用空间
{
construct(m_Finish, *(m_Finish - ));//在备用空间中构造一个
m_Finish++;//调整备用空间剩余容量
T ElementCpoy = Element;//将要插入的节点进行拷贝
/*调用全局函数,为要插入的节点移出一块内存空间*/
copy_backward(Position, m_Finish - , m_Finish - );
*Position = ElementCpoy;//将节点插入
}
else//没有备用空间了
{
const SizeType uiOldSize = Size();//计算原来空间的长度
/*得到需要的长度,若原来大小不为零,则新开辟的大小应该为其原本大小的两倍,反之则为1*/
const SizeType uiLen = uiOldSize != ? * uiOldSize : ;
Iterator NewStart = DataAllocator::Allocate(uiLen);//开辟内存并且将新的内存地址保存
Iterator NewFinish = NewStart;
try
{
/*将vector中的数据拷贝到新的vector内存中*/
NewFinish = uninitialized_copy(m_Start, Position, NewStart);
/*为新的元素设定值*/
construct(NewFinish, Element);
++NewFinish;
/*将备用空间的内容也拷贝过来,这可能没什么用!!*/
NewFinish = uninitialized_copy(Position, m_Finish, NewFinish);
}
catch(...)
{
destroy(NewStart, NewFinish);
DataAllocator::Deallocate(NewStart, uiLen);
throw;
} destroy(Begin(), End());
Deallocate(); m_Start = NewStart;
m_Finish = NewFinish;
m_EndOfStorage = NewStart + uiLen;
}
} #endif
以上代码更多的是为自己的学习做个笔记,欢迎交流讨论!
2、vector的实现的更多相关文章
- c++ vector 使用
1. 包含一个头文件: 1 #include <vector> 2. 申明及初始化: std::vector<int> first; // empty vector of in ...
- Vector Tile
Mapbox Vector Tile Specification A specification for encoding tiled vector data. <?XML:NAMESPACE ...
- ArrayList、Vector、LinkedList的区别联系?
1.ArrayList.Vector.LinkedList类都是java.util包中,均为可伸缩数组. 2.ArrayList和Vector底层都是数组实现的,所以,索引数据快,删除.插入数据慢. ...
- ArrayList、Vector、HashMap、HashSet的默认初始容量、加载因子、扩容增量
当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复制到新的内存上,这无疑使效率大大降低. 加载因 ...
- Java中Vector和ArrayList的区别
首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList.Vector和LinkedList.List用于存放多个元素,能够维护元素的次序,并且允许元素的重复.3个具体 ...
- C++使用vector
#include <iostream> #include <string> #include <vector> using namespace std; void ...
- [LeetCode] Flatten 2D Vector 压平二维向量
Implement an iterator to flatten a 2d vector. For example,Given 2d vector = [ [1,2], [3], [4,5,6] ] ...
- C++ 数组array与vector的比较
转:http://blog.csdn.net/yukin_xue/article/details/7391897 1. array 定义的时候必须定义数组的元素个数;而vector 不需要: 且只能包 ...
- vector定义初始化
头文件 #include<vector> using std::vector; vector<T> v1; vector<T> v2(v1); vector< ...
- vector迭代器用法
#include<iostream> #include<vector> using namespace std; int main() { vector<int> ...
随机推荐
- 使用indent命令帮助排版源代码
在写代码时候,特别是在vim中编辑代码时候,你可能会不太注意代码风格问题,比如‘{’符号放在行末还是下一行行首等等, 这样你把自己代码与别人的代码merge时候,就会出现代码风格不一的问题,这里就推荐 ...
- ZendFramework2 源码分析 init_autoloader.php
// Composer autoloading if (file_exists('vendor/autoload.php')) { // 加载自动加载器 $loader = include 'vend ...
- wget 测试cdn
可以通过wget 或curl 指定代理ip来访问同一个链接的不同cdn响应页面.来测试不同cdn间的数据同步问题.
- linux下mysql忘记root密码的解决方案
1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库. 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态下,其他的用户也可以任意地登录 ...
- 全 Javascript 的 Web 开发架构:MEAN
http://developer.51cto.com/art/201404/434759.htm 全 Javascript 的 Web 开发架构:MEAN 引言 最近在Angular社区的原型开发者间 ...
- poj 3318 Matrix Multiplication
http://poj.org/problem?id=3318 矩阵A*矩阵B是否等于矩阵C #include <cstdio> #include <cstring> #incl ...
- 使用docker打造spark集群
前提条件:安装好了docker,见我的另一篇博客,Docker安装 有两种方式, Spark官方repo里,docker文件夹下的脚本.官方的这个脚本封装很薄,尽可能把必要的信息展示出来. AMPLa ...
- Windows下安装使用curl命令
1 进入http://curl.haxx.se/download/?C=M;O=D网站 2 根据自己的操作系统位数和是否需要SSL下载相应的版本.这里下载curl-7.33.0-win64-ssl-s ...
- css案例学习之div+a实现菜单
效果 代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w ...
- app行业发展趋势
近日,移动开放平台发布了2014年第一季度App开发行业报告.报告中对目前国内app开发者的分布情况,个人开发者和企业开发者的开发领域,相应比例以及提交应用过程中出现的问题做出统计,为如何建立一个更好 ...