很长一段时间没有动手编写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. mysql 表级锁

    表级锁:分为读锁和写锁: lock tables table_name read;//其他事务只能读,不能加写锁,要等待更新. SESSION 50 执行: mysql> update test ...

  2. USACO 2005 January Gold The Wedding Juicer

    题目 题目链接,我只在poj上找到了题目,usaco居然上不去. 大意就是说有一些\(1\times 1\times 1\)的小方块堆在一起,问最多能装多少水. 我们在一次测试中出了这题,由于我写水题 ...

  3. MySQL 修改字段类型或长度

    mysql> alter table 表名 modify column 字段名 类型;例如 数据库中address表 city字段是varchar(30) 修改类型可以用(谨慎修改类型,可能会导 ...

  4. NGUI 3.5教程(二)Label 标签 (Hello world)、多行文本

    写在前面:     本文将创建NGUI的第一个样例.依照编程传统,第一个样例,就是做一个Hello world 显示出来.NGUI.我们用Label来实现 . 欢迎大家纠错.拍砖!原创非常辛苦,如有转 ...

  5. cloudflare的新waf,用Lua实现的

    我们使用nginx贯穿了我们的网络,做前线web服务,代理,流量过滤.在某些情况下,我们已经扩充了nginx上我们自己的模块的核心C代码,但近期我们做了一个重大举措,与nginx结合使用lua 差点儿 ...

  6. Google C++ style guide——命名约定

    1.通过命名规则 函数命名.变量命名.文件命名应具有描写叙述性. 类型和变量应该是名词,函数名能够用"命令性"动词. 2.文件命名 文件名称所有小写,能够包括下划线(_)或者断线( ...

  7. android Gallery滑动不流畅的解决

    import android.content.Context; import android.util.AttributeSet; import android.view.KeyEvent; impo ...

  8. CxSkinButton按钮皮肤类

    在codeproject 发现一个很强大的按钮皮肤类,之前的版本有内存泄露,但是作者已经修复了,原文网址是:http://www.codeproject.com/KB/buttons/cxskinbu ...

  9. iOS- 如何集成支付宝

    链接地址:http://www.cnblogs.com/qingche/p/3556365.html 现在不少app内都集成了支付宝功能   使用支付宝进行一个完整的支付功能,大致有以下步骤: 1&g ...

  10. CentOS查看端口是否被占用

    CentOS查看端口是否被占用 本文介绍了linux中查看某一端口是否被占用的方法,有关netstat命令的使用技巧,感兴趣的朋友可以参考下. 使用命令: netstat -tunlp 会显示所有端口 ...