C++易vector
很长一段时间没有动手编写C++计划。无非就是模仿后STL对,虽然达不到标准STL该程序。但简单的功能来实现。
STL事实上,深刻:泛型编程、容器、算法、适配器...有的是内容能够学。以下是依据STL源代码。写的一个非常easy的vector,实现了部分接口。事实上vector还是相对非常easy的容器了,元素按在内存中连续排列,仅仅须要三个指针就能实现非常多的接口。另一个就是内存的分配,这里採用了一个C++提供的allocator配置器。所以分配起来还是蛮简单的,SGI版本号的STL中的配置器为了达到效率的极致,使用了另外的分配器。相当复杂。这里就没有写了。
#ifndef __MYVECTOR_H__
#define __MYVECTOR_H__ template <class T>
class Vector {
public:
typedef T value_type;
typedef value_type* iterator; // vector的迭代器就是原生指针
typedef value_type* pointer;
typedef value_type& reference;
typedef size_t size_type; public:
Vector() : start(NULL), finish(NULL), end_of_storage(NULL)
{
} Vector(size_type n, const value_type &value)
{
start = alloc.allocate(n);
end_of_storage = finish = start + n;
uninitialized_fill_n(start, n, value);
} Vector(size_type n)
{
start = alloc.allocate(n);
end_of_storage = finish = start + n;
uninitialized_fill_n(start, n, value_type());
} ~Vector()
{
// 顺序调用元素的析构函数
for (iterator i = start; i != finish; ++i)
alloc.destroy(i); // 销毁分配的空间
if (start != NULL)
alloc.deallocate(start, end_of_storage - start);
} iterator begin() const
{
return start;
} iterator end() const
{
return finish;
} size_type size() const
{
return end() - begin(); // 使用接口函数,包裹性更好
} size_type capacity() const
{
return end_of_storage - begin(); // 使用接口函数。包裹性更好
} bool empty() const
{
return begin() == end();
} // 返回的引用可被改动
reference front()
{
return *(begin());
} // 返回的引用可被改动
reference back()
{
return *(end() - 1);
} reference operator[] (const size_type n)
{
return *(begin() + n);
} const reference operator[] (const size_type n) const
{
return *(begin() + n);
} void push_back(const value_type &value)
{
if (finish == end_of_storage)
reallocate(); // 存储空间已满。则又一次分配内存
alloc.construct(finish, value);
++finish;
} void reallocate(); void pop_back()
{
--finish;
alloc.destroy(finish); // 析构最后一个函数,但不释放空间
} // 清除一个元素
iterator erase(iterator position)
{
if (position + 1 != finish)
copy(position + 1, finish, position);
--finish;
alloc.destroy(finish);
return position;
} // 清除一段元素
iterator erase(iterator first, iterator last)
{
if (first < start || last > finish)
throw exception("Invalid input."); copy(last, finish, first);
int len = last - first;
while (len--)
alloc.destroy(--finish);
return first;
} void clear()
{
erase(begin(), end());
} private:
iterator start;
iterator finish;
iterator end_of_storage; private:
static std::allocator<value_type> alloc; // 空间配置器。採用静态属性节省空间
}; template <class Type>
std::allocator<Type> Vector<Type>::alloc; template <class Type>
void Vector<Type>::reallocate()
{
size_type oldsize = size();
size_type newsize = 2 * (oldsize == 0 ? 1 : oldsize); // 分配新的内存空间
iterator newstart = alloc.allocate(newsize);
uninitialized_copy(start, finish, newstart); // 顺序调用每一个元素的析构函数
for (iterator i = start; i != finish; ++i)
alloc.destroy(i); // 销毁分配的空间,销毁之前主要检查是否为NULL
if (start != NULL)
alloc.deallocate(start, end_of_storage - start); // 更新下标
start = newstart;
finish = start + oldsize;
end_of_storage = start + newsize;
} #endif
insert操作应该算是最复杂的一个接口了,设计到元素的搬移、(可能)又一次分配内存等等,这里我仅仅实现了一个最简单的形式:
template <class Type>
void Vector<Type>::insert(iterator position, const value_type &value)
{
size_type diff = position - start; if (finish == end_of_storage)
reallocate(); position = start + diff; // 注意,这里不能使用copy。由于目的地最后一个位置还没有被构造,
// 赋值涉及析构操作,对未构造的对象进行析构,行为没有定义
alloc.construct(finish, *(finish - 1));
++finish;
copy_backward(position, finish - 1, finish); // 不能使用uninitialized_copy。由于这个函数是从前向后构造。这会造成覆盖
//uninitialized_copy(position, finish, position + 1); // 插入新对象,直接赋值就可以
*position = value;
}
測试程序:
int main()
{
Vector<int> v; v.push_back(1);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.push_back(2);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.push_back(3);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.push_back(4);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.push_back(5);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; Vector<int>::iterator iter1 = v.begin();
Vector<int>::iterator iter2 = iter1 + 3;
v.erase(iter1, iter2); cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.clear();
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; v.push_back(123);
cout << "size = " << v.size() << endl;
cout << "capacity = " << v.capacity() << endl; for (Vector<int>::iterator iter = v.begin(); iter != v.end(); ++iter)
cout << *iter << endl; system("pause");
return 0;
}
执行结果:
參考:
《STL源代码剖析》
《C++ primer》
版权声明:本文博客原创文章。博客,未经同意,不得转载。
C++易vector的更多相关文章
- 几道c/c++练习题
1.以下三条输出语句分别输出什么?[C易] char str1[] = "abc"; char str2[] = "abc"; const char str3[ ...
- C++开发工程师面试题库 50~100道
51. New delete 与malloc free 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作.用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对 ...
- C++笔试题库之编程、问答题 150~200道
151.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值 int a = 4; (A)a += (a++); (B) a += (++a) ;(C) (a++) += a;( ...
- 嵌入式开发—C语言面试题
嵌入式开发—C语言面试题 源地址:http://blog.csdn.net/xdx2ct1314/article/details/7358929 1. 用预处理指令#define 声明一个常数,用 ...
- CSharpGL(0)一个易学易用的C#版OpenGL
+BIT祝威+悄悄在此留下版了个权的信说: CSharpGL(0)一个易学易用的C#版OpenGL CSharpGL是我受到SharpGL的启发,在整理了SharpGL,GLM,SharpFont等开 ...
- 剑指Offer——网易笔试之解救小易
知识要点 首先介绍一下曼哈顿,曼哈顿是一个极为繁华的街区,高楼林立,街道纵横,从A地点到达B地点没有直线路径,必须绕道,而且至少要经C地点,走AC和 CB才能到达,由于街道很规则,ACB就像一个直角3 ...
- Java 常用数据结构深入分析(Vector、ArrayList、List、Map)
线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...
- STL中vector,Map,Set的实现原理
vector的数据安排以及操作方式,与array非常类似,两者唯一的区别是空间运用的灵活性,array是静态空间,一旦配置了就不能改变,如果你想要大一点的空间,就必须首先配置一块新空间,然后将原来的元 ...
- 细节!重点!易错点!--面试java基础篇(二)
今天来给大家分享一下java的重点易错点第二部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.字符串创建与存储机制:当创建一个字符串时,首先会在常量池中查找是否已经有相同的字符串被定义,其判断 ...
随机推荐
- Android 播放声音
public static void PlayAlarmRing(Context mContext) { Uri alert = RingtoneManager.getDefaultUri(Ringt ...
- (读书笔记).NET大局观-.NET框架类库概观
.NET框架类库概况 构建在.NET框架上所有的软件,都会用到通用语言进行时,即使基于最简单的CLR程序,也需要用到一部分.NET框架类库,更精致复杂的软件则使用这个类库提供的更多服务. .NET框架 ...
- 我的Android进阶之旅------>HTTP 返回状态值详解
(本文转载于:http://blog.csdn.net/ithomer/article/details/10240351) 当用户点击或搜索引擎向网站服务器发出浏览请求时,服务器将返回Http Hea ...
- 关于android中postDelayed方法的讲解
这是一种可以创建多线程消息的函数使用方法:1,首先创建一个Handler对象 Handler handler=new Handler(); 2,然后创建一个Runnable对象Runnable run ...
- em换算px
一般浏览器默认的1em=16px,所以常用字体大小如下: 10px=0.625em 12px=0.75em 14px=0.875em 16px=1em 18px=1.125em 20px=1.25em ...
- Ubuntu中查看硬盘分区UUID的方法(所有Linux目录的解释)
在Ubuntu中UUID的两种获取方法,至于UUID是什么,你可以大概理解为分区的标识符,像条形码那样. 在终端中输入下面的命令就可心查看到分区UUID了.命令1.sudo blkid 命令2.ls ...
- 查询mysql哪些表正在被锁状态
1.查进程,主要是查找被锁表的那个进程的ID SHOW PROCESSLIST; 2.kill掉锁表的进程ID KILL 10866;//后面的数字即时进程的ID
- 在JS中,一个自定义函数如何调用另一个自定义函数中的变量
function aa1511() { var chengshi="马鞍山"; var shengfen="安徽省"; return shengfen+&quo ...
- OpenGL框架+QT版
原地址:http://blog.chinaunix.net/uid-25799257-id-3498005.html 之前一直做地图的算法,没什么时间学习opengl,之前看nehe_OpenGL.c ...
- Java面试宝典2014版
一. Java基础部分......................................................................................... ...