STL 中的 vector 容器就是一个基于模板泛型的动态数组,它和原生数组不同的之处在于:原生数组在定义时需要指定长度,无法随着需要自动增长,而动态数组则可以根据元素个数自动扩展内存。动态数组可以使用 C 来实现,但是为了能够支持更多的数据类型,使用 C++ 模板技术来实现会更灵活。
动态数组最核心的是其动态增长策略,原理也较为简单:
- 在数组实现时,引入容量概念。即:为了避免频繁的 new/delete 耗时的操作,我们可以在扩展内存时,一次申请较大的空间。
- 插入元素时,先判断是否容量足够。如果不足,则扩展内存。如果充足,则直接插入元素。这里需要注意的是:扩展内存就是申请一块更大的内存,需要将原空间的数据拷贝到新空间,为了避免内存泄漏,原数据空间需要及时释放。
- 添加到容器中的元素必须支持拷贝语义,即:元素必须能够被拷贝。
下面是具体实现代码:
template<class T>
class DynamicArray
{
public:
// 默认构造
DynamicArray(size_t capacity = 2);
// 有参构造
DynamicArray(std::initializer_list<T> list);
// 拷贝构造
DynamicArray(const DynamicArray<T> &arr);
// 移动构造
DynamicArray(DynamicArray<T> &&arr);
// 普通赋值
DynamicArray<T>& operator=(const DynamicArray<T> &arr);
// 移动赋值
DynamicArray<T>& operator=(DynamicArray<T> &&arr);
// 添加元素
void push_back(const T &ele);
// 删除元素
void remove(const T &ele);
// 重载下标
T& operator[](int index) const;
// 数组大小
size_t size() const;
// 析构函数
~DynamicArray();
public:
T *p_data; // 数据空间
size_t m_capacity; // 当前数组容量
size_t m_size; // 当前数组元素个数
};
函数实现代码:
// 默认构造
template<class T>
DynamicArray<T>::DynamicArray(size_t capacity)
{
std::cout << "默认构造" << std::endl;
this->m_capacity = capacity;
this->m_size = 0;
this->p_data = new T[m_capacity];
}
// 有参构造
template<class T>
DynamicArray<T>::DynamicArray(std::initializer_list<T> ele_list)
{
std::cout << "有参构造" << std::endl;
this->m_capacity = ele_list.size();
this->m_size = ele_list.size();
this->p_data = new T[this->m_capacity];
size_t i = 0;
for (auto it = ele_list.begin(); it < ele_list.end(); ++it)
{
this->p_data[i++] = *it;
}
}
// 拷贝构造
template<class T>
DynamicArray<T>::DynamicArray(const DynamicArray<T> &arr)
{
std::cout << "拷贝构造" << std::endl;
// 拷贝属性
this->m_capacity = arr.m_capacity;
this->m_size = arr.m_size;
// 拷贝数据
this->p_data = new T[this->m_capacity];
for (int i = 0; i < this->m_size; ++i)
{
this->p_data[i] = arr.p_data[i];
}
}
// 移动构造
template<class T>
DynamicArray<T>::DynamicArray(DynamicArray<T> &&arr)
{
std::cout << "移动构造" << std::endl;
this->m_capacity = arr.m_capacity;
this->m_size = arr.m_size;
this->p_data = arr.p_data;
arr.p_data = nullptr;
arr.m_capacity = 0;
arr.m_size = 0;
}
// 普通赋值
template<class T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray<T>& arr)
{
std::cout << "普通赋值" << std::endl;
// 拷贝属性
this->m_capacity = arr.m_capacity;
this->m_size = arr.m_size;
// 如果对象拥有原数据,则释放
if (this->p_data != nullptr)
{
delete[] this->p_data;
this->p_data = nullptr;
}
// 拷贝数据
this->p_data = new T[this->m_capacity];
for (int i = 0; i < arr.m_size; ++i)
{
this->p_data[i] = arr.p_data[i];
}
return *this;
}
// 移动赋值
template<class T>
DynamicArray<T>& DynamicArray<T>::operator=(DynamicArray<T> &&arr)
{
std::cout << "移动赋值" << std::endl;
this->m_capacity = arr.m_capacity;
this->m_size = arr.m_size;
if (this->p_data != nullptr)
{
delete[] this->p_data;
p_data = nullptr;
}
this->p_data = arr.p_data;
arr.p_data = nullptr;
arr.m_capacity = 0;
arr.m_size = 0;
return *this;
}
// 添加元素
template<class T>
void DynamicArray<T>::push_back(const T &ele)
{
if (m_capacity == m_size)
{
// 扩展空间,默认2倍扩展(可自定义策略)
size_t new_capacity = m_capacity * 2;
T* new_data = new T[new_capacity];
// 原空间数据拷贝到新空间
for (int i = 0; i < m_size; ++i)
{
new_data[i] = this->p_data[i];
}
// 释放原空间
if (this->p_data != nullptr)
{
delete[] this->p_data;
this->p_data = nullptr;
}
this->m_capacity = new_capacity;
this->p_data = new_data;
}
// 新元素拷贝到容器中
this->p_data[this->m_size++] = ele;
}
// 删除元素
template<class T>
void DynamicArray<T>::remove(const T& ele)
{
// 查找元素
int i = 0;
bool flag = false;
for (;i < m_size; ++i)
{
if (p_data[i] == ele)
{
flag = true;
break;
}
}
// 删除元素
if (flag)
{
for (int j = i; j < m_size - 1; ++j)
{
p_data[j] = p_data[j + 1];
}
--m_size;
}
}
template<class T>
T& DynamicArray<T>::operator[](int index) const
{
return p_data[index];
}
// 数组大小
template<class T>
size_t DynamicArray<T>::size() const
{
return m_size;
}
// 析构函数
template<class T>
DynamicArray<T>::~DynamicArray()
{
std::cout << "析构函数" << std::endl;
if (this->p_data != nullptr)
{
delete[] this->p_data;
this->p_data = nullptr;
this->m_size = 0;
this->m_capacity = 0;
}
}

冀公网安备13050302001966号