通过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有时候会花费大量的时间。作为一个菜鸡,写的文章水平也相当有限,因此如果有不对的地方,我斗胆请各位大佬对菜鸡新人写的文章的错误进行批评指正。还有其他不足的地方还请多多包涵

### dhtmlxGantt.js 中 `duration` 属性的使用 在 dhtmlxGantt.js 库中,`duration` 属性用于表示任务持续时间。此属性通常与特定的任务对象关联,并影响甘特图上的显示效果。 对于编辑器配置,可以设置如下: ```javascript var durationEditor = { type: "number", map_to: "duration", min: 0, max: 100 }; ``` 上述代码片段展示了如何创建一个名为 `durationEditor` 的变量来定义输入控件的行为[^1]。该控件允许用户通过界面调整任务的持续时间,范围限定于 0 到 100 单位之间(具体单位取决于应用上下文)。这种设定有助于确保数据有效性并提供直观的操作体验给最终使用者。 为了更好地理解 `duration` 属性的应用场景及其与其他功能模块之间的交互方式,下面给出一段完整的 JavaScript 实现示例,它不仅涵盖了基本的任务管理还包括了 UI 状态保持机制以及样式适配等内容: #### 创建和初始化甘特图实例 首先,在 HTML 文件内引入必要的资源文件之后,可以通过以下脚本启动一个新的甘特图实例: ```javascript gantt.init("gantt_here"); gantt.config.xml_date = "%Y-%m-%d %H:%i"; // 设置默认视图模式和其他全局参数... ``` 这里假设有一个 ID 为 `"gantt_here"` 的 DOM 元素作为图表渲染的目标区域;同时指定了日期格式化字符串以便后续解析 XML 数据源时能够正确识别时间戳信息。 #### 配置任务字段映射关系 接着要做的就是告诉 gantt 组件哪些自定义属性应该被用来填充内部模型结构。这一步骤涉及到修改 `config.lightbox.sections` 和其他相关选项以适应项目需求: ```javascript gantt.attachEvent("onLightbox", function (id) { var task = gantt.getTask(id); // 动态更新 lightbox 表单内的初始值 }); gantt.config.columns = [ {name:"text", label:"Task name", tree:true, width:200}, {name:"start_date", label:"Start time", align:"center"}, {name:"duration", label:"Duration", align:"center"} ]; ``` 这段代码设置了表格列布局,并明确了每一列表头对应的键名。值得注意的是,“duration” 字段在这里得到了特别处理——其标签名称设为 “Duration”,并且居中对齐显示数值型内容。 #### 处理工具栏事件及保存状态 考虑到用户体验方面的要求,每当点击全展/收起按钮时都应当同步记录当前分支的状态变化情况: ```javascript document.getElementById('expandAll').addEventListener('click', function () { gantt.expand(); saveBranchesState(); }); document.getElementById('collapseAll').addEventListener('click', function () { gantt.collapse(); saveBranchesState(); }); ``` 以上逻辑实现了监听指定元素触发的动作,并调用了相应的 API 方法完成节点操作的同时还执行了一次额外的状态存盘动作[^2]。 #### 调整容器尺寸以支持响应式设计 最后但同样重要的一点是要保证甘特图能够在不同设备屏幕上正常呈现出来。为此需遵循官方文档建议的做法即赋予外部包裹层合适的宽高比例约束条件: ```css html, body{ margin:0px; padding:0px; height:100%; /*强制*/ overflow:hidden; } #gantt_here{ position:relative; width:100%; height:100%; } ``` 这些 CSS 规则确保即使是在移动端浏览器环境下也能获得良好的视觉反馈效果[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值