前段时间写了一个通过C++ array类简单了解C++容器初始化机制_Harris_ayaka的博客-CSDN博客,现在我整理一下C++ array中具体细节。
详情参考array 类(C++ 标准库) | Microsoft Docs
array类首先是语法:
templateclass array;
接收两个模板参数,并且将数组的尺寸作为模板参数之一,因此两个不同大小但元素类型相同的的array将被视为不同的类型,例如:
arraya1; array a2;
将被视为不同的类型。
成员0、private成员
这是作为array容器的基础,一个是指向数组首地址的指针,一个是数组的size
template1、构造函数class array { private: Type* list; size_t size; ..... }
visual studio 2022的文档有两个构造函数:
即是正常的构造函数与复制构造函数
array(); array(const array& right);
但参考我的上一篇通过C++ array类简单了解C++容器初始化机制_Harris_ayaka的博客-CSDN博客
我还加上了一个带参的构造函数:
array(const std::initializer_list&r);
用于使用大括号初始化array对象:
arraynums{ 1,2,3,}; //用这样的形式初始化必须重载一个参数带initializer_list的函数
下面介绍三种构造函数的具体实现细节:
首先是默认构造函数,不带任何参数
templatearray ::array() { size = N; list = new Type[N]; _begin = list; _end = list + N; }
在这里,我有一个还未解决的问题:
众所周知,如果一个变量声明在主函数外面,那么他是一个全局变量,并且这个变量会被自动初始化,代码如下
#include#include using namespace std; array a; int main() { for (int i = 0; i < 10; ++i) { cout << a[i] << endl; } }
输出结果如图:
但是我在使用自定义的array类的时候,声明全局变量,并不会被初始化
#include"array.h" #includeusing std::cout; using std::cin; using std::endl; using namespace ayaka; array a; int main() { for (int i = 0; i < 10; ++i) { cout << a[i] << endl; } }
结果如下,可以看到全部都是奇怪的值。希望这个问题有大佬能够帮我解答一下: )
接下来是复制构造函数:
复制构造函数不能采用简单的把另一个变量赋值给该类,详情可以去自行了解一下深复制与浅复制机制
templatearray array ::operator=(const array & right) { size = N; list = new Type[N]; _begin = list; _end = list + N;//迭代器要用的组件,后文会详细介绍 for (int i = 0; i < size; ++i) { list[i] = right.list[i]; } }
最后是能够使用初始化列表的构造函数:
template2、析构函数array ::array(const std::initializer_list & r) { size = N; list = new Type[N]; _begin = list; _end = list + N; auto it = r.begin(); for (size_t i = 0; i < r.size(); ++i) { list[i] = *it++; } if (N > r.size()) { for (size_t i = r.size(); i < N; ++i) { list[i] = Type(); } } }
众所周知,析构函数的作用是销毁对象,我们先来看看如果不写析构函数,调用默认的析构函数效果如何
#include"array.h" #includeusing std::cout; using std::cin; using std::endl; using namespace ayaka; int main() { const size_t n = 10; array nums{ 1,2,3,}; array a(nums); a.~array (); for (int i = 0; i < 10; ++i) { cout << a[i] << endl; } }
运行结果发现这个析构函数就是个摆设,运行结果如下:
因此有必要自己动手重写一些析构函数:
~array() {
delete[]list;
size = 0;
_begin = nullptr;
_end = nullptr;//释放数组占用的空间,并且将size归0
}
3、迭代器
C++继承了C语言的指针,在array类中,指针和迭代器可以看做是同一个东西,因此也不用去重载++,--,+,-等运算符,C指针本身就支持这些运算
但为了和保证接口相同即使用iterator来调用迭代器,因此要使用typedef,具体方法如下:
public: typedef Type* iterator; iterator begin(); iterator end(); private: iterator _end; iterator _begin;
在外部使用:
array::iterator it;
begin()与end()
template成员函数:Type* array ::begin() { return _begin; } template Type* array ::end() { return _end; } //_begin是数组的首地址,_end是数组的尾地址
1、at()
templateType& array ::at(size_t off) {//不检查下标 return*(list + off); } template const Type& array ::at(size_t off) const { return*(list + off); }
2、assign()//C++ 11中已经过时,用fill替代,于是我就不写这个了
3、fill()
void fill(const Type& val);
templatevoid fill(const Type& val) { for (int i = 0; i < size; ++i) { list[i] = val; } }
至于其他的
back():返回最后一个元素
front():返回第一个元素
empty():返回容器是否为空等等,感觉没有什么必要写
运算符重载最重要的是"[]"和"="两个运算符,至于其他运算符尤其是比较运算符,我个人感觉实用性不强,而且实现原理简单所以没必要写。
1、[]运算符
//定义 Type& operator[](size_t i); const Type& operator[](size_t i)const; //实现直接利用上文提到的at函数,实现起来比较简单,又非常好用 templateconst Type& array ::operator[](size_t i)const { return at(i); } template Type& array ::operator[](size_t i) { return at(i); }
2、=运算符
templatearray array ::operator=(const array & right) { for (int i = 0; i < size; ++i) { list[i] = right.list[i]; } return *this }
测试一下:
#include"array.h" #includeusing std::cout; using std::cin; using std::endl; using namespace ayaka; int main() { const size_t n = 10; array nums{ 1,2,3, }; array a; a = nums; for (int i = 0; i < 10; ++i) { cout << a[i] << endl; } }
运行结果:
得到了正确的结果
非成员函数1、swap()
交换两个数组的首地址,并且迭代器也需要重新赋值
template//声明 friend void swap(array & left, array & right); //定义 template void swap(array & left, array & right) { Type* p = left.list; left.list = right.list; right.list = p; left._begin = left.list; right._begin = right.list; left._end = left.list + N; right._end = right.list + N; }
测试一下
#include"array.h" #includeusing std::cout; using std::cin; using std::endl; using namespace ayaka; int main() { const size_t n = 10; array nums{ 1,2,3, }; array a; a.fill(114514); swap(a, nums); for (int i = 0; i < n; i++) { cout << a[i] << endl; } }
运行结果如下:
得到了正确的结果
2、get()
templateType& get(array & arr) { return arr[i]; } template constexpr const Type& get(const array & arr)noexcept { return arr[i]; } template constexpr Type&& get(const array & arr) noexcept { return arr[i]; }
使用方式如下:
#include"array.h" #include#include using std::cout; using std::cin; using std::endl; using namespace ayaka; int main() { const size_t n = 10; array nums{ 1,2,3, }; array a; a = nums; int c = get<5>(a); cout << c << endl; }
其中get
这次通过手动实现array,了解了一些静态数组的机制,后面应该还会写一个在为array定义迭代器的过程中遇到的C++范围for循环的机制。辣鸡程序员,如有问题烦请各位大佬批评指正。



