很长一段时间没有动手编写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的更多相关文章

  1. 几道c/c++练习题

    1.以下三条输出语句分别输出什么?[C易] char str1[] = "abc"; char str2[] = "abc"; const char str3[ ...

  2. C++开发工程师面试题库 50~100道

    51. New delete 与malloc free 的联系与区别?答案:都是在堆(heap)上进行动态的内存操作.用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对 ...

  3. C++笔试题库之编程、问答题 150~200道

    151.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值 int a = 4; (A)a += (a++); (B) a += (++a) ;(C) (a++) += a;( ...

  4. 嵌入式开发—C语言面试题

    嵌入式开发—C语言面试题 源地址:http://blog.csdn.net/xdx2ct1314/article/details/7358929   1. 用预处理指令#define 声明一个常数,用 ...

  5. CSharpGL(0)一个易学易用的C#版OpenGL

    +BIT祝威+悄悄在此留下版了个权的信说: CSharpGL(0)一个易学易用的C#版OpenGL CSharpGL是我受到SharpGL的启发,在整理了SharpGL,GLM,SharpFont等开 ...

  6. 剑指Offer——网易笔试之解救小易

    知识要点 首先介绍一下曼哈顿,曼哈顿是一个极为繁华的街区,高楼林立,街道纵横,从A地点到达B地点没有直线路径,必须绕道,而且至少要经C地点,走AC和 CB才能到达,由于街道很规则,ACB就像一个直角3 ...

  7. Java 常用数据结构深入分析(Vector、ArrayList、List、Map)

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

  8. STL中vector,Map,Set的实现原理

    vector的数据安排以及操作方式,与array非常类似,两者唯一的区别是空间运用的灵活性,array是静态空间,一旦配置了就不能改变,如果你想要大一点的空间,就必须首先配置一块新空间,然后将原来的元 ...

  9. 细节!重点!易错点!--面试java基础篇(二)

    今天来给大家分享一下java的重点易错点第二部分,也是各位同学面试需要准备的,欢迎大家交流指正. 1.字符串创建与存储机制:当创建一个字符串时,首先会在常量池中查找是否已经有相同的字符串被定义,其判断 ...

随机推荐

  1. linux系统文件属性-硬连接、软连接

    1 硬链接概念 硬链接是指通过索引节点(Inode)来进行链接,在Linux(ext2,ext3)文件系统中,保存在磁盘分区中的文件不管是什么类型都会给它分配一个编号,这个编号被称为索引节点编号(In ...

  2. mysql 创建表 create table详解

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ...

  3. Codeforces Round #189 (Div. 2)

    题目地址:http://codeforces.com/contest/320 第一题:基本题,判断mod 1000,mod 100.,mod 10是不是等于144.14.1,直到为0 代码如下: #i ...

  4. struts2之高危远程代码执行漏洞,可造成服务器被入侵,下载最新版本进行修复

          Struts2 被发现存在新的高危远程代码执行漏洞,可造成服务器被入侵,只要是Struts2版本 低于 2.3.14.3 全部存在此漏洞.目前官方已经发布了最新的版本进行修复.请将stru ...

  5. C#由变量捕获引起对闭包

    C#由变量捕获引起对闭包的思考   前言 偶尔翻翻书籍看看原理性的东西确实有点枯燥,之前有看到园中有位园友说到3-6年工作经验的人应该了解的.NET知识,其中就有一点是关于C#中的闭包,其实早之前在看 ...

  6. maven setting配置

    <?xml version="1.0" encoding="UTF-8"?> <!--Licensed to the Apache Softw ...

  7. 使用 jackson序列格式化日期

    [1]自定义时间,序列化类 [java] view plaincopy package com.fsti.bm.utils; import java.io.IOException; import ja ...

  8. Eclipse中使用版本控制----Git

    之前在做软件开发的过程中使用的版本控制软件大多是cvs,svn等等,这些都属于cvcs,及中央版本控制系统,其特点是存在一个中央库,开发者首先从中央库中下载代码,编辑,然后提交.很明显的一个特点就是使 ...

  9. attachEvent与addEventlistener兼容性

    关于原生事件绑定中attachEvent与addEventlistener中兼容性以及attachEvent函数中this指代window有关问题   请点击下面回答中的"采纳为答案&quo ...

  10. PHP中遍历stdclass object 及 json 总结[中国航天神舟十号以json形式向地面返回数据]

    $test=Array ( [0] => stdClass Object ( [tags] => 最快的车,Bloodhound,SSC [id] => 48326888 11 从网 ...