通过C++ array类简单了解C++容器初始化机制

最近为了让自己深入了解C++,于是开始动手实现C++的一些简单的常用组件,在基本完成了最简单的链表、栈、队列等数据结构之后,我又挑了一个最简单的,开始实现C++的静态数组array类

参考文档:​​​​​​<array> 函数 | Microsoft Docs

array

C++的array是一个定长静态数组,声明如下。接收两个模板参数:元素类型,一个是数组长度。把数组长度也作为模板参数之一,数组长度不能修改,如果要改变数组长度,那还是使用vector或者deque吧

template <class Ty, std::size_t N>
class array;

定长数组类似于C风格的数组,支持随机访问,插入删除时间复杂度O(n),随机访问时间复杂度O(1)。整体难说实现过程没有什么难点,我在这个过程中遇到的唯一遇到的问题,就是使用初始化列表初始化一个array

首先看一下array的构造函数:这是上面提到的visual studio官方文档给的构造函数,一个是默认的构造函数,一个是复制构造函数。于是我就照着写了

array();

array(const array& right);

我在继续阅读的时候,发现了如下初始化形式:通过一个初始化列表,来初始化array,如果初始化列表中的元素个数小于array的size,那么array中剩下的元素会被赋默认初始值。

array<int, 4> ai = { 1, 2, 3 };

简单提一下什么是默认初始值:一般在变量声明为全局变量的时候,都会被赋与默认初始值,比如在main函数外面声明了一个int x; x会被自动初始化为0,关于初始化机制,简单来说就是如果是数值类型,默认初始值为0,如果是字符串类型,初始值就是个空串,如果是指针应该就是一个nullptr等等之类的

初始化列表initializer_list

但是我在实现了文档中提到的两种构造函数形式之后,并不能使用上述代码那样的初始化列表

const size_t n = 10;
array<int,n> nums{ 1,2,3,};
//有报错:无法从“initializer list”转换为“ayaka::array<int,10>”

 在查阅资料之后,才知道要写一个参数是initializer_list的构造函数

于是简要了解一下initializer_list,

#include <initializer_list>
template <class Type>
class initializer_list{
    ...
}

只接收一个模板参数,需要包含头文件<initializer_list>,同时不支持随机访问,支持使用迭代器顺序访问。因此可以先不管原理,直接把它当成一个顺序容器,用迭代器访问即可

初始化列表赋值实现

根据上述思路,写出了array的构造函数如下

array(const std::initializer_list<Type> &r);//声明
template <class Type, size_t N>
array<Type, N>::array(const std::initializer_list<Type>& r) {
	size = N;
	list = new Type[N];
	auto it = r.begin();
	for (size_t i = 0; i < r.size(); ++i) {
		list[i] = *it++;
	}
}

这样就使用了初始化列表给array赋与初始值,接下来测试一下效果

#include<iostream>
#include"array.h"
using std::cout;
using std::cin;
using std::endl;
using namespace ayaka;
int main() {
	const size_t n = 10;
	array<int,n> nums{ 1,2,3,};
	for (int i = 0; i < n;++i){
		cout << nums[i] << endl;
	}
}

很显然,只有前三个被初始化了,后面全是奇怪的值。改用std库的array看看

#include<iostream>
#include<array>
using std::cout;
using std::cin;
using std::endl;

int main() {
	const size_t n = 10;
	std::array<int,n> nums{ 1,2,3,};
	for (int i = 0; i < n;++i){
		cout << nums[i] << endl;
	}
}

 

 然而标准库的array其余的值得到了正确的默认初始化的值。这里我又遇到了一个问题,当初始化列表的size小于array.size的时候,如何给剩下的值进行默认初始化

查阅资料之后回想起来:C++可以通过Type()来调用某个类型的对象的初始值,例如我们想获取int的初始值,可以这样写:

int x = int()

看上去类似于调用类的默认的构造函数

因此要解决上述问题就很简单了:稍微改造一下上述构造函数,剩余的值就调用Type()即可

template <class Type, size_t N>
array<Type, N>::array(const std::initializer_list<Type>& 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();
		}
	}
}

总结

使用列表初始化是C++11的一个新特性,对于C++标准库中能够使用大括号赋初值的容器,基本上都是利用initializer_list实现的。在这次实现array的过程中,让我简单的理解了这一个特性背后的原理。比起分享某一个知识点,这篇文章的重点还是在于记录我个人学习中遇到的障碍,虽然写出来可能用不了多久,但解决一些bug有时候会花费大量的时间。作为一个菜鸡,写的文章水平也相当有限,因此如果有不对的地方,我斗胆请各位大佬对菜鸡新人写的文章的错误进行批评指正。还有其他不足的地方还请多多包涵

  • 31
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值