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

【C++11保姆级教程】列表初始化(Literal types)和委派构造函数(delegating)) C++11引入了许多新的语言特性和标准库扩展,这些变化使得C++编程更加强大和便捷。其中,列表初始化和委派构造函数是C++11中引入的两个重要特性。本文将深入探讨列表初始化和委派构造函数的概念、用法以及示例代码,帮助读者更好地理解和应用这些特性。在上述示例中,我们定义了一个Rectangle(矩形)类,它具有三个构造函数:默认构造函数、边长相同的构造函数和指定宽高的构造函数。在默认构造函数和边长相同的构造函数中,我们使用委派构造函数的方式,将初始化逻辑委派给指定宽高的构造函数。 阅读详情

目录

一,列表初始化

{ }初始化

优势

使用场景

二,类模板列表初始化

库模板初始化列表实现

模拟模板初始化列表实现


        在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能更好地用于系统开放和库开发,语法更加泛化和简单化,更加稳定和安全,不仅功能强大,而且能提升程序员的开发效率;

一,列表初始化

        列表初始化(List Initialization)是一种 C++11 引入的一种统一的初始化语法,可用来初始化各种类型的对象,包括数组、结构体、类以及容器等;提供了更安全、更一致的初始化方式,能够应用于各种初始化场景;

        具体来说,列表初始化使用花括号 {} 将一组值括起来,用逗号分隔各个元素,形成一个初始化列表;注意与类成员初始化列表(如:_a(a))的区别;

{ }初始化

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

//C环境
/*struct Point
{
    int _x, _y;
};*/
int arr[] = {1, 2, 3, 4, 5};
int arr[5] = {0};
Point p = { 1, 2 };

//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};

//标准容器,调用initializer list构造函数
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};

优势

  • 统一的初始化语法,可用于几乎所有初始化场景;
// 变量初始化
int x{5};
// 动态分配内存
int* p = new int{10};
// 函数返回值
std::vector<int> makeVec() {
    return {1, 2, 3};  // 返回列表初始化
}
// 类成员初始化
class Widget {
    std::vector<int> data{1, 2, 3};  // 成员初始化
};
  • 防止窄化转换(Narrowing Conversion),即不允许可能导致数据丢失的隐式类型转换;
int a = 3.14;    // 警告但允许,a=3
int b{3.14};     // 错误!窄化转换从double到int

char c{1000};    // 错误!窄化转换(如果char是8位)
unsigned u{-1};  // 错误!窄化转换
  • 避免最令人烦恼的解析(Most Vexing Parse);
class Timer;
// 传统语法可能被解析为函数声明
Timer t();  // 函数声明,返回Timer对象
// 列表初始化明确表示对象初始化
Timer t{};  // 明确初始化Timer对象

使用场景

  • 容器初的始化;

//标准容器,调用initializer list构造函数
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}};
  • 自定义类型的初始化,会尝试调用匹配的构造函数;

class Point
{
public:
	Point(int x=0,int y=0)
		:_x(x), _y(y)
	{}
private:
	int _x, _y;
};

int main()
{
    //以下等价,构造函数参数列表与大括号内元素个数一致
	Point p(1, 2);
	Point p1 = { 1, 2 };   
    Point p2{ 1, 2 };
}

  • 聚合类初始化,即没有用户定义的构造函数、没有私有/受保护的非静态成员等);

//struct或class
struct Aggregate {
    int x;
    double y;
    std::string name;
};

Aggregate a{10, 3.14, "test"};  // 聚合初始化

二,类模板列表初始化

  • 要支持初始化列表,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数;
    • 所有现代STL容器都支持initializer_list构造函数,方便实现任意数量参数的函数;
      • 如序列式容器(array、vector、deque、list、forward_list),关联式容器(set/multiset、map/multimap、unordered_set/unordered_multiset、unordered_map/unordered_multimap);
      • 容器适配器(stack、queue、priority_queue)不支持,但可在构造时传递容器;
    • initializer_list是轻量级容器,不管理内存,只是底层数组的视图;
    • 元素是const,不能修改;
    • 廉价的拷贝,拷贝操作通常共享底层数据;
    • 比普通构造函数优先级更高;
  • initializer_list是系统自定义的类模板,该类模板中主要有三个方法:
    • begin()、end()迭代器;
    • 获取区间中元素个数的方法size();

  • Initializer list 类型用于访问初始化列表中的值;
  • Initializer list 类型对象由编译器从初始化列表声明(用大括号括起来的逗号分隔的元素列表)中自动构造,即{value1,value2,...}会自动构造一个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;
};
std::initializer_list<int> li = { 1,2,3,4 };
std::cout << li.size() << std::endl;
for (auto i = li.begin(); i != li.end(); i++)
{
	std::cout << *i << std::endl;
}
template<class T>
class Point
{
public:
	Point(T x, T y)
		:_x(x), _y(y)
	{
		cout << "Point(int x = 0, int y = 0)" << endl;
	}

	Point(std::initializer_list<T> li)
	{
		_x = *(li.begin());
		_y = *(li.begin()+1);
		cout << "Point(std::initialier_list<T> li)" << endl;
	}
private:
	T _x, _y;
};

int main()
{
	Point<int> p = { 1,2 }; //优先使用Point(std::initializer_list<T> li)
}

库模板初始化列表构造函数的实现

  • 调用对应的初始化列表构造函数,然后将初始化列表值循环将元素赋值到对象内;
//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;
}

C++中的列表(List)数据结构详解及示例代码 在C++编程中,列表(List)是一种常用的数据结构,用于存储一系列元素。本文将详细介绍C++中列表的使用方法,并提供相应的示例代码。通过以上示例,我们已经了解了C++中列表的基本用法。在实际应用中,我们可以根据具体需求选择不同的列表操作来满足我们的编程需求。要访问列表中的元素,可以使用迭代器(iterator)。在上面的示例中,我们创建了一个整数类型的列表,并添加了三个元素:10、20和30。在上面的代码中,我们分别从列表的末尾和开头删除了一个元素。在上面的示例中,我们使用下标运算符访问了列表。 阅读详情

相关推荐

C++11新特性之列表初始化

文章目录**1、统一的初始化方法****2、列表初始化的一些使用细节****3、初始化列表****4、列表初始化防止类型收窄** 在我们实际编程中,我们经常会碰到变量初始化的问题,对于不同的变量初始化的手段多种多样,比如说对于一个数组我们可以使用 int arr[] = {1,2,3}的方式初始化,又比如对于一个简单的结构体: struct A { int x; int y; }a = {1,2}; 这些不同的初始化方法都有各自的适用范围和作用,且对于类来说不能用这种初始化的方法,最主要的是没有一种可

二进制君 9232

【C++】-- 初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式。

局部变量和全局变量 2万+

System Verilog学习笔记(十九)——覆盖率

覆盖率是用来衡量验证精度和完备性的数据指标。也可以告诉我们在仿真时设计的哪些结构被触发,哪些没被触发。高质量的验证需要满足以下三个条件。

ljy77882333的博客 2142

C++基础——初始化列表

C++初始化列表讲解

weixin_69283129的博客 6540

LabVIEW事件结构避坑指南:为什么你的‘确定按钮’事件有时会失灵?

本文深入探讨了LabVIEW事件结构中'确定按钮'事件失灵的常见原因及解决方案。从事件队列机制到事件类型选择,详细分析了事件丢失的五大原因,包括事件处理耗时过长、事件类型选择不当等,并提供了优化登录界面案例的实用建议。掌握这些技巧可显著提升LabVIEW用户界面的响应可靠性。

weixin_42548888的博客 353

Ghost备份还原Win10全攻略:从老电脑迁移到新硬盘,ESP分区处理是关键

本文详细介绍了使用Ghost工具将Win10系统从旧电脑迁移到新硬盘的全过程,特别强调了ESP分区的关键处理方法。通过分步指导备份、分区准备、系统还原和引导修复,帮助用户实现无缝系统迁移,解决常见问题如启动失败和驱动兼容性。

weixin_30823001的博客 672

【C++进阶】C++11的新特性 | 列表初始化 | 可变模板参数 | 新的类功能

本文介绍了C++11标准中的新特性,重点讲解了列表初始化的相关内容。 在列表初始化方面,C++11扩展了C++98中{}初始化的使用范围,使其可以用于一切对象的初始化,包括内置类型和自定义类型。文章通过代码示例展示了如何使用{}初始化各种类型对象,并解释了背后的优化原理。 特别介绍了std::initializer_list类,这是STL容器支持列表初始化的关键。通过initializer_list,容器可以方便地接受任意多个值的初始化列表。文章还展示了容器如何利用initializer_list实现初始化

Linux、C++、图形软件开发等。不一定每次都能写出完美的代码,但会认真搞懂每一个问题。 1409

光谱数据计算CIE值(三刺激值、CIE1931、CIE1976、CCT)软件

软件界面如下,免安装,拷贝即可使用 导入光谱数据即可计算三刺激值、CIE1931、CIE1976、CCT CIE1931、CIE1976色坐标图形只管显示 导入的光谱数据格式如下,txt文本 波长380到780,间隔1nm 注意:缺省的数据默认写0即可 下面为一些CIE相关介绍: CIE(国际发光照明委员会):原文为Commission Internationale de L’Eclairage(法)或International Commission on Illumination(英)。这个委员会创

业余程序员小徐的博客 2万+

【初阶与进阶C++详解】第二十二篇:C++11新特性(列表初始化+变量类型推到+右值引用+新增默认成员函数+可变模板参数+lambda表达式+包装器function_bind)

C++11是2011年更新的C++新语法,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。[capture-list]捕捉列表,用于编译器判断是否是lambda表达式,同时捕捉该表达式所在域的变量以供函数使用(parameters)参数,和函数的参数一致。如果不需要传参则可连带()一起省略mutable默认情况下捕捉列表捕捉的参数是const修饰的,该关键字的作用是取消const使其可修改。

YQ20210216的博客 996

linux离线安装nginx

linux离线安装nginx

zhang_130914036的博客 9347

微信小程序 - 引入并使用 Fly.js 请求库(超级详细的教程及运行示例)提供 Fly.js 源码源文件下载,贴心的配置示例及注释,优雅快速的发起 http 网络请求

fly.js请求库官方教程文档,微信小程序封装fly.js请求,在小程序/mpvue中使用flyio发起网络请求的方法,微信小程序中如何使用flyio封装网络请求,微信小程序中如何使用flyio封装网络请求,最好的教程,fly最好的文档教程,微信小程序使用fly接口请求框架,引入fly.js报错,微信小程序中如何使用flyio封装网络请求,微信小程序引入Fly.js请求库,如何在fly中配置请求/响应拦截器,如何在微信小程序中优雅地发送异步请求,请求/响应拦截器,微信小程序-引入并使用F

🏆 前端领域优质创作者 5608

C++进阶知识复习 16~30

C++进阶知识总结2

小萌新的博客 1061

黑猫带你学eMMC协议第9篇:eMMC初始化过程(initial)

本文依据eMMC JEDEC5.1及个人工作经验整理而成,如有错误请留言。 文章为个人辛苦整理,付费内容,禁止私自转载。 文章所在专栏:《黑猫带你学:eMMC协议详解》 1 什么是emmc的初始化 对于小白来说,可能不太明白什么是emmc初始化。举个栗子:当你拿到一个电脑,接上电源,是不是就立马可以用了呢?并不是吧,你还需要去开机,等待电脑启动,配置完各种参数,等出现了电脑桌面,你才能用。那么同样,对于emmc芯片来说,也不是提供电源就能用了,需要输入各种命令后,让其进入到tran state后,才能正.

黑猫奥利奥的博客 6738

C++进阶:C++11相关

本文摘要:C++11新特性解析 本文系统讲解了C++11中的关键新特性: 列表初始化:统一了内置类型和自定义类型的初始化方式,引入initializer_list支持容器初始化 右值引用:区分左值/右值,通过移动语义优化资源管理,减少拷贝开销 类型分类:细化右值为纯右值和将亡值 完美转发:利用引用折叠规则和forward保留参数原始类型特性 重点分析了移动构造/移动赋值的实现原理,以及右值引用在函数返回值和参数传递中的性能优化作用。通过示例代码展示了这些特性在实际开发中的应用场景和优势。

新人博主,欢迎大家互三、交流学习! 677

UniApp 覆盖安装后首次进入 APP pages.json 不生效的解决方案

通过以上步骤,解决了缓存问题导致的首次加载异常。此方案的关键在于强制更新文件名,从根本上避免旧缓存的干扰。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 681

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

《C++进阶之C++11》【列表初始化 + 右值引用】

本文摘要: 文章介绍了C++11引入的列表初始化和右值引用两大特性。文中通过代码示例展示了列表初始化在数组、结构体和容器中的实际应用,并对比了C++98与C++11的初始化差异。这些特性显著提升了C++代码的简洁性和性能,是现代化C++编程的重要基础。

序属秋秋秋的博客 1728

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【CPP11新特性,列表初始化】列表初始化与初始化列表是不是一个概念?列表是怎么初始化的?

CPP11列表初始化语法点介绍,列表初始化与初始化列表概念?列表是怎么初始化的简单介绍。

BinaryWiker的博客 1300

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【C++杂货铺】C++11特性总结:列表初始化 | 声明 | STL的升级

本篇文章介绍了C++11中的三个新特性:列表初始化、声明、STL的升级

春人.的博客 6519

C++11 就地初始化与列表初始化

C++11之前,C++主要有以下几种初始化方式://小括号初始化 string str(&amp;amp;quot;hello&amp;amp;quot;);//等号初始化 string str=&amp;amp;quot;hello&amp;amp;quot;;//大括号初始化 struct Studnet{ char* name; int age; }; Studnet s={&amp;amp;quot;dablelv&amp

Doublelv 的博客专栏。 1万+

C++11列表初始化 {}

C++11引入的列表初始化{}提供了一种统一、安全的初始化方式,具有以下核心特性:1)统一语法,适用于基本类型、数组、结构体、类和容器;2)禁止窄化转换,防止数据精度丢失;3)支持通过std::initializer_list实现容器批量初始化。相较于传统初始化方式,列表初始化显著简化了代码,提高了安全性,特别是在容器初始化和类型转换方面表现突出。该特性使C++的初始化语法更加现代化和规范化。

TTKunn的博客 1649

【C++】——C++11新特性

C++,这门在系统开发、游戏开发、嵌入式等众多领域都占据主导地位的编程语言,一直在不断进化。C++11就像是C++家族中的一颗璀璨明星,闪耀着无数令人惊叹的新特性。如果你还在使用传统的C++编码方式,那你可能正在错过许多现代编程的便捷与高效。想象一下,用更少的代码编写出性能更高的程序,轻松应对复杂的并发场景,还能享受更加简洁和安全的内存管理。C++11就能让这一切成为现实。在这篇博文中,我会一点点揭开C++11新特性的神秘面纱,让你看到C++在这次重大更新之后所蕴含的无限潜力。

2402_85267481的博客 1874

【C++11】列表初始化

详细讲解C++11——列表初始化

tan_run的博客 1077

【C++11】:统一的列表初始化|声明|STL变化

对于c++11新特性的总结( ´◔︎ ‸◔︎`)

B1ue还在专注 1966

【C++】C++11新特性的讲解

C++11简介在2003年C++标准委员会曾经提交了一份技术勘误表简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于C++98/03C++11。

Sxy_wspsby的博客 1242

【C++课程学习】:C++11(C++发展,列表初始化,声明auto,typeid,decltype)

(下面介绍来源于---文心一言)⛳️起源阶段:1979年,丹麦计算机科学家比雅尼·斯特劳斯特鲁普(Bjarne Stroustrup)发现C语言在表达能力、可维性和可展性方面的不足,开始对其进行了一系列的改进。斯特劳斯特鲁普在贝尔实验室开始从事将C改良为带类的C()的工作。他希望开发一个既要编程简单、正确可靠,又要运行高效、可移植的计算机程序设计语言。而以C语言为背景,以Simula思想为基础的语言,正好符合他的初衷和设想。

路虽远,行则将至!事虽难,做则必成! 4977
上一篇: C++进阶 —— multimap
下一篇: C++进阶 —— 范围for(C++11新特性)
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值