2 - 初始化列表initializer_list

在学习函数模板之前,先看看初始化列表initializer_list

介绍

就是初始化列表,在<initializer_list>中被定义,可以用它来初始化各种容器,例如vector,数组等。

使用

初始化容器

// 左值初始化
std::initializer_list<int> iList{ 1, 2, 3, 4, 5 };
std::vector<int> iVec(iList);
// 右值初始化
std::vector<int> iVec2 = { 1, 2, 3, 4, 5 };

作为函数参数

以上篇文章中的类模板为例,新建构造函数:

// 左值和右值版本
template<typename T>
MyArray<T>::MyArray(const std::initializer_list<T>& list)
{
	if (list.size())
	{
		unsigned length = 0;
		data = new T[list.size()]();

		// 用萃取技术判断是不是指针类型,防止浅拷贝
		if (std::is_pointer<T>::value)
		{
			for (auto elem : list)
			{
				// 用模板特化技术判断是什么类型的指针
				data[length++] = new typename get_type<T>::type(*elem);
			}
		}
		else
		{
			for (const auto& elem : list)
			{
				data[length++] = elem;
			}
		}
	}
	else
	{
		data = nullptr;
	}
}

template<typename T>
MyArray<T>::MyArray(std::initializer_list<T>&& list)
{
	if (list.size())
	{
		unsigned length = 0;
		data = new T[list.size()]();
		for (const auto& elem : list)
		{
			data[length++] = elem;
		}
	}
	else
	{
		data = nullptr;
	}
}

记得添加以下内容,突然多了萃取技术跟模板特化有点懵:

// 萃取技术
#include <type_traits>
// 模板特化(解决从int*知道是int类型的指针)
template<typename T>
struct get_type
{
	using type = T;
};

template<typename T>
struct get_type<T*>
{
	using type = T;
};

然后就能在main函数中使用了:

int i1 = 10;
int i2 = 20;
std::initializer_list<int*> iList{ &i1, &i2 };

MyArray<int*> arrayPi1(iList);
MyArray<int*> arrayPi2(std::move(iList));

for (unsigned i = 0; i < 2; i++)
{
	std::cout << *arrayPi1[i] << std::endl;
	std::cout << *arrayPi2[i] << std::endl;
}

注意:这里出现了内存泄漏,原因是类型为int*,导致没有把二次指针的内存给释放掉。如果使用智能指针/容器(vector)的话就好了。

参考资料

  • 飘零的落花 - 现代C++详解
  • C++20高级编程