数据结构还是很早之前学的了,当时才刚学过C语言,实现得都很简单,最近决定重新打牢基础,于是重新开始实现书上的数据结构和算法。

模仿C++ Primer的StrVec以及std::vector,使用模板类+allocater分配内存,遵循“三/五原则”,期间遇到了几个小问题,记录下。

1、unsigned和signed的比较:

在实现insert操作时,写了个私有方法去把数组index处开始的元素向后移动n位。分两种情况处理,一种是容量不够需要重新分配内存,另一种是容量足够,直接向后移动。

前一种分配内存空间后可以直接用uninitialized_copy搬运元素,也可以用Allocater::construct构造元素。而后一种是在原先分配的内存上重新构造元素,因此要注意先更新的位置就不要再使用。

如上图,把index为1开始的元素向后移动1位。如果从前往后移动,第一次就会改动位置2处的元素,但是位置2处的元素需要移动到位置3处,这样就造成了错误。

因此需要从后移动,我之前的代码就是  for (size_t i = count - 1; i >= index; --i)

乍看之下没有问题,但是在index为0的时候就出错了。size_t是unsigned int,假如是为0再自减,会变成unsigned包含的最大的数,具体原因我之前写过一篇博客说过。

C语言的补码表示和unsigned及signed的转换

所以我把size_t改成了int,代码变成  for (int i = count - 1; i >= index; --i)

但是依旧出错,调试发现:int i = -1; unsigned index = 0; 那么i > index为true。其实编译器已经把问题提出来了:warning c4018 : signed/unsigned mismatch
signed和unsigned进行比较时会都转换成unsigned比较,也就是说虽然i自减成了负数,但是进行比较时会被强制转换为unsigned,这个循环依旧是个死循环。

解决方法:

1、把index强制转换为int,这样就会是signed之间比较;

2、改成for (int i = 0; i < count - index; ++i)然后改变循环体内关于i的部分,这样比较麻烦,而且i不能直接体现出表达的意义。

2、类模板中定义友元函数

如果友元函数的定义在类中则没有什么问题,如果要写在类的外部就有点麻烦。以下面代码为例。

template <typename T>
class SqList; template <typename T>
std::ostream &operator<<(std::ostream &, const SqList<T> &); template <typename T>
class SqList
{
friend std::ostream &operator<< <T>(std::ostream &, const SqList<T> &);
// ...
} template <typename T>
std::ostream &operator<< (std::ostream &os, const SqList<T> &lst)
{
for (auto iter = lst.begin(); iter != lst.end(); ++iter)
os << *iter << ' ';
return os;
}

首先,友元函数需要在类之前进行声明,这点跟普通类的友元函数不同(具体原因需要复习下模板的知识,暂不深究)。而由于友元函数会用到类模板作为参数,所以必须再对类模板进行前置声明。

其次,模板类的友元函数本质上是个函数模板,因此在类模板中进行友元声明时在函数名后用模板参数实例化,否则就会出现经典的外部链接错误error LINK 2019,因为会判断类外部的函数实现(operator<<)并不是对类内的operator<<的实现,所以在调用这个友元方法时编译器找不到定义。

模仿std::vector写线性表的几点感想的更多相关文章

  1. [C++]使用vector描述线性表定义及基本操作

    #ifndef VECTORLIST_H #define VECTORLIST_H #include<iostream> #include"linearlist.h" ...

  2. C++编程练习(1)----“实现简单的线性表的顺序存储结构“

    线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素. 故可以用数组来实现顺序存储结构. 用C++编写的利用数组实现简单的读取.插入和删除功能的线性表. #include< ...

  3. 随机排序std::vector,扑克牌,麻将类尤其合用

    有些需要重新对std::vector对象重新排序,特别是游戏,例如说:扑克牌,麻将,抽奖等,C++标准已经为std::vector写好了随机排序的方式,这里做个笔记: #include <alg ...

  4. JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)

    Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...

  5. 已知长度为n的线性表采用顺序结构,写一算法删除该线性表中所有值为item的元素

    /** * @author:(LiberHome) * @date:Created in 2019/2/27 23:34 * @description: * @version:$ */ /*已知长度为 ...

  6. 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路

    01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...

  7. Java数据结构之线性表

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

  8. [置顶] ※数据结构※→☆线性表结构(queue)☆============循环队列 顺序存储结构(queue circular sequence)(十)

    循环队列 为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量.存储在其中的队列称为循环队列(Circular Queue). ...

  9. c++转载系列 std::vector模板库用法介绍

    来源:http://blog.csdn.net/phoebin/article/details/3864590 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作 ...

随机推荐

  1. js排序算法06——希尔排序

    希尔排序本质是一种插入排序,由一位叫希尔的大神提出得名,其基本思想是将数组分组进行插入排序,每次消除不止一个逆序对,这样就提高了插入排序的效率.最后一步进行一间隔的插入排序,此时数组已经基本有序.代码 ...

  2. 常用js、jquery 语句(句型)

    1.动态更改设置属性(class  style 都是属性) $("#sendPhoneNum").attr("class", "n_input3&qu ...

  3. C++复习11.函数的高级特性

    C++ 函数的高级特性 20131002 C++函数增加了重载(override), inline, const, virtual四种机制,重载和内联机制既可以用于全局函数,也可以用于类的成员函数.c ...

  4. java程序设计基础篇 复习笔记 第六单元

    第六章 一维数组 1 数组初始化语法 array initializer 2 for each loop 3 off-by-one error 通常是在循环中该使用<的地方使用了<= 4 ...

  5. 转载:【Oracle 集群】RAC知识图文详细教程(一)--集群概念介绍

    文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...

  6. String类运算符重载,自己实现

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  7. CUDA Samples: green ball

    以下CUDA sample是分别用C++和CUDA实现的生成的绿色的球图像,并对其中使用到的CUDA函数进行了解说,code参考了<GPU高性能编程CUDA实战>一书的第五章,各个文件内容 ...

  8. boost split字符串

    boost split string , which is very convenience #include <string> #include <iostream> #in ...

  9. 用sublime server 启动本地服务器(手机访问电脑页面)

    安装sublime server 插件包           1.Ctrl + shift + p                      install package               ...

  10. Swift 发送邮件和发短信

    // MARK: - Action // MARK: compose mail 发送邮件 @IBAction func composeMail(sender: AnyObject) { // 判断能否 ...