C++进阶 —— 列表初始化(C++11新特性)

本文围绕C++11的列表初始化特性展开。介绍了C++标准的发展,对比C++98/03,C++11有诸多新特性。详细阐述了列表初始化,包括其在C++98和C++11中的使用差异,还介绍了类列表初始化及类模板列表初始化,包含库模板和模拟模板的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,列表初始化

二,类列表初始化

三,类模板列表初始化

库模板初始化列表实现

模拟模板初始化列表实现


        在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称;不过由于TC1主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯的把两个标准合称为C++98/03标准;从C++0x到C++11,C++标准十年磨一剑,第二个真正意义上的标准姗姗来迟; 相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言;相比较而言,C++11能更好地用于系统开放和库开发,语法更加泛化和简单化,更加稳定和安全,不仅功能强大,而且能提升程序员的开发效率;

一,列表初始化

        列表初始化是一种 C++11 中引入的新特性,可用来初始化各种类型的对象,包括数组、结构体、类以及容器等。具体来说,列表初始化使用花括号 {} 将一组值括起来,用逗号分隔各个元素,形成一个初始化列表;注意与初始化列表(r如:_a(a))的区别;

{ }初始化

        在C++98中,标准允许使用{}对数组元素进行统一的列表初始化设定;但对一些自定义类型不可这样使用,无法编译,导致每次定义vector时,都需要先定义vector,在循环对其赋初始值,非常不方便;

int arr[] = {1, 2, 3, 4, 5};
int arr[5] = {0};
//c++98中不可这样使用,需循环赋值
vector<int> v = {1, 2, 3, 4, 5};

        C++11扩大了用大括号{}括起来的列表(初始化)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加;

编译器会对大括号中的元素进行类型检查,不符合要求即报错;

  • 元素类型与被初始化对象类型匹配;
  • 对自定义类型大括号内的元素个数与被初始化对象构造函数参数个数匹配;
//内置类型
int x = 10;
int x = {10};
int x{10};

int x = 1+2;
int x = {1+2};
int x{1+2};

//数组
int arr[5] = {1,2,3,4,5};
int arr[] = {1,2,3,4,5};
int arr[]{1,2,3,4,5};

//动态数组,C++98不支持
int* parr = new int[5]{1,2,3,4,5};
int* parr = new int[]{1,2,3,4,5};

//标准容器
vector<int> v1{ 1, 2, 3, 4, 5 };
vector<int> v2={ 1, 2, 3, 4, 5 };
map<int, int> m{{1,1},{2,2},{3,3},{4,4}};

        对于内置类型,列表初始化在某些情况下可能会导致不同的行为,特别是当涉及到类型推导;通常推荐使用直接初始化(如int x = 5)或统一初始化(C++11引入的int x{5});

auto x = {5}; //实际类型为std::initializer_list<int>
int x = 5; //直接初始化
int x{5};

二,类列表初始化

  • 编译器尝试匹配构造函数,该构造函数参数列表与大括号内元素个数一致;
class Point
{
public:
	Point(int x=0,int y=0)
		:_x(x)
		,_y(y)
	{}
private:
	int _x;
	int _y;
};

int main()
{
    //以下等价
	Point p(1, 2);
	Point p1 = { 1, 2 };   
    Point p2{ 1, 2 };
}

三,类模板列表初始化

  • 要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数;
  • initializer_list是系统自定义的类模板,该类模板中主要有三个方法,begin()、end()迭代器,以及获取区间中元素个数的方法size();

  • Initializer list 类型用于访问初始化列表中的值;
  • Initializer list 类型对象由编译器从初始化列表声明(用大括号括起来的逗号分隔的元素列表中自动构造;
//库定义
template <class _Elem>
class initializer_list 
{
public:
    ...
    constexpr initializer_list() noexcept : _First(nullptr), _Last(nullptr) {}
    constexpr initializer_list(const _Elem* _First_arg, const _Elem* _Last_arg) noexcept
        : _First(_First_arg), _Last(_Last_arg) {}
    _NODISCARD constexpr const _Elem* begin() const noexcept {return _First;}
    _NODISCARD constexpr const _Elem* end() const noexcept {return _Last;}
    _NODISCARD constexpr size_t size() const noexcept {return static_cast<size_t>(_Last - _First);}
private:
    const _Elem* _First;
    const _Elem* _Last;
};

库模板初始化列表实现

  • 调用对应的初始化列表构造函数;
  • 然后将初始化列表值循环赋值对象;
//vector库模板,初始化列表构造函数	
_CONSTEXPR20_CONTAINER vector(initializer_list<_Ty> _Ilist, const _Alloc& _Al = _Alloc())
	: _Mypair(_One_then_variadic_args_t{}, _Al)
{
	auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
	_Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2);
    //初始化列表赋值
	_Range_construct_or_tidy(_Ilist.begin(), _Ilist.end(), random_access_iterator_tag{});
	_Proxy._Release();
}

template <class _Iter>
_CONSTEXPR20_CONTAINER void _Range_construct_or_tidy(_Iter _First, _Iter _Last, input_iterator_tag) {
	_Tidy_guard<vector> _Guard{ this };
	for (; _First != _Last; ++_First) {
		emplace_back(*_First); // performance note: emplace_back()'s strong guarantee is unnecessary here
	}
	_Guard._Target = nullptr;
}

模拟模板初始化列表实现

#include<initializer_list>
template<class T>
class MyVector
{
public:
	MyVector(std::initializer_list<T> lt)
		:_capacity(lt.size())
		,_size(0)
	{
		_array = new T[_capacity];
		for (auto e : lt)
			_array[_size++] = e;
	}
	
	MyVector<T>& operator=(std::initializer_list<T> lt)
	{
		delete[] _array;

        _capacity = lt.size();
        _array = new T[_capacity];
		_size = 0;
		for (auto e : lt)
			_array[_size++] = e;

		return *this;
	}
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};

int main()
{
    //以下三种形式等价
    MyVector<int> v1({ 1,2,3 });
	MyVector<int> v2 = { 1,2,3 };
	MyVector<int> v3{ 1,2,3 };
    //调用operator=
	v1 = { 3,2,1 };
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值