1、StaticList类模板
StaticList
的设计要点:类模板
- 使用原生数组作为顺序存储空间
- 使用模板参数决定数组大小
template <typename T, int N>
class StaticList : public SeqList<T>
{
protected:
T m_space[N]; // 顺序存储空间,N为模板参数
public:
StaticList() // 指定父类成员的具体值
{
this->m_array = m_space;
this->m_length = 0;
}
int capacity() const
{
return N;
}
};
2、DynamicList类模板
DynamicList
设计要点:类模板
- 申请连续堆空间作为顺序存储空间
- 动态设置顺序存储空间的大小
- 保证重置顺序存储空间时的异常安全性
异常安全性的概念:
- 不泄露任何资源
- 不允许破坏数据
函数异常安全的基本保证:如果异常被抛出
- 对象内的任何成员任然能保持有效状态
- 没有数据的破坏及资源泄漏
DynamicList
类模板:
template <typename T>
class DynamicList : public SeqList<T>
{
protected:
int m_capacity; // 顺序存储空间的大小
public:
DynamicList(int capacity) // 申请空间,构造函数参数作为大小
{
this->m_array = new T[capacity];
if ( this->m_array != NULL)
{
// 堆空间申请成功
this->m_length = 0;
this->m_capacity = capacity;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to creat DynamicList object...");
}
}
int capacity() const
{
return m_capacity;
}
/* 重新设置顺序存储空间的大小 */
void resize(int capacity)
{
if (capacity != m_capacity)
{
T* array = new T[capacity];
// 为什么不直接操作this->m_array
// 因为要保证数据的完整性,设置了空间大小 ,原来的数据不变
if( array != NULL)
{
int length = (this->m_length < capacity ? this->m_length : capacity);
for (int i = 0; i < length; i++)
{
// 复制数据元素
array[i] = this->m_array[i];
// 这里也可能发生异常,但是也不会怎样,当前的线性表对象不会发生改变,只是array会被泄漏
// 如果这里发生异常,说明泛指类型T所指代的具体类型所导致的,是第三方工程师代码问题
}
// delete this->m_array;
// 没有直接操作this->m_array,是因为有可能在析构的时候会发生异常,函数异常返回,导致this->m_array等没法赋值,这就没法保证当前的线性表this->m_array合法可用
// 思路是先用一个临时指针指向原先的顺序存储空间,然后将线性表赋值,改为重置之后的线性表,然后再delete[] temp,这时就算再发生异常,线性表也是合法可用的
T* temp = this->m_array;
this->m_array = array;
this->m_length = length;
this->m_capacity = capacity;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to resize DynamicList object...");
}
}
}
~DynamicList()
{
delete[] this->m_array;
}
};
3、小结
StaticList
通过模板参数定义顺序存储空间
DynamicList
通过动态内存申请定义顺序存储空间
DynamicList
支持动态重置顺序存储空间的大小
DynamicList
中的resize()
函数实现需要保证异常安全