【C++练级之路】【Lv.21】C++11——列表初始化和声明

2024-05-26 11:28

本文主要是介绍【C++练级之路】【Lv.21】C++11——列表初始化和声明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、列表初始化
    • 1.1 内置类型
    • 1.2 结构体或类
    • 1.3 容器
  • 二、声明
    • 2.1 auto
    • 2.2 decltype
    • 2.3 nullptr
  • 三、STL的变化
    • 3.1 新增容器
    • 3.2 新增initializer_list构造
    • 3.3 新增移动构造、移动赋值和移动插入
    • 3.4 其他

引言

关于C++11的auto、nullptr和范围for的知识,在之前已经提到过,这里不再赘述,有需要的请移步这篇博客【C++练级之路】【Lv.1】C++,启动!(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for,nullptr)

一、列表初始化

C++11更新后,一切皆可用列表初始化。列表初始化,又称统一初始化,具体使用{}进行初始化。

列表初始化,沿袭C语言对于内置类型和结构体的初始化上,进行了统一形式的扩展。

1.1 内置类型

void test()
{//单一变量int i = 0;int j = { 0 };int k{ 0 };//数组int arr1[] = { 1,2,3 };int arr2[5]{ 0 };//动态开辟int* ptr1 = new int[5] {0};
}

虽然内置类型(如 int, double 等)通常不需要列表初始化,但列表初始化仍然允许。列表初始化的一个特点,就是可以去除等号“=”。

1.2 结构体或类

struct Point
{int _x, _y;
};class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}
private:int _year, _month, _day;
};void test()
{//结构体Point p1 = { 3,5 };Point p2{ 4,6 };//类Date d1(2024, 4, 10);Date d2 = { 2024,5,1 };Date d3{ 2024,6,1 };//动态开辟Date* ptr2 = new Date[3]{ d1,d2,d3 };Date* ptr3 = new Date[3]{ {2024,1,1},{2024,2,2},{2024,3,3} };
}

对于类的列表初始化,可以理解为隐式类型转换构造临时对象->拷贝构造->编译器优化为直接构造

1.3 容器

void test()
{vector<int> v1 = { 1,2,3 };vector<int> v2 = { 1,2,3,4,5 };map<string, string> dict = { {"排序","sort"},{"逆序","reverse"} };
}

对于容器的列表初始化,可不是之前的类型转换,因为此时初始化的列表是可以变长的,而之前的多参数构造是固定长度的。


那么,此时应该怎么理解容器的列表初始化呢?其实,这里涉及了STL库中的initializer_list类。

void test()
{auto il = { 1,2,3,4,5 };cout << typeid(il).name() << endl;initializer_list<int>::iterator it = il.begin();while (it != il.end()){cout << *it << " ";++it;}cout << endl;for (auto e : il){cout << e << " ";}cout << endl;
}

由上述代码可知,让编译器自动推导列表类型,便是class std::initializer_list< int >。同样的,initializer_list类也有自己的迭代器,可以用迭代器进行遍历和修改。


那么,每次容器的列表初始化过程可以理解为:将右侧构造为initializer_list ->遍历initializer_list,进行迭代器区间构造

  1. 构造initializer_list的过程:在常量区找到列表中的值,用两个指针start和finish指向头部和尾部的下一位(类似于vector的内部原理)
  2. 每个容器都添加了initializer_list的构造函数,调用对应的构造函数,运用迭代器区间进行容器构造

ps:容器既有initializer_list的构造,也有initializer_list的赋值

二、声明

C++11提供了多种简化声明的方式,尤其是在使用模板时。

2.1 auto

2.2 decltype

关键字decltype可将变量的类型声明为表达式指定的类型

void test()
{int x = 1;double y = 2.0;decltype(x) k;auto ret = x * y;vector<decltype(ret)> v;
}

decltype最大的作用,便是用来定义模板参数。因为auto没办法作为模板参数,所以decltype正好弥补了这方面的缺陷。

2.3 nullptr

三、STL的变化

3.1 新增容器

C++11更新了四个容器,分别是array,forward_list,unordered_set,unordered_map。其中unordered_set,unordered_map,我们已经深入学习和模拟实现过了。

那么,关于array和forward_list,其实带来的提升较小,实际中较少用到。

  • array:array是一个固定大小的容器,它在编译时就知道自己的大小,这使得它在性能上通常优于vector,因为它不需要在运行时进行动态内存分配和大小调整。

  • forward_list:forward_list是一个单向链表,它只包含指向下一个元素的指针,没有指向前一个元素的指针。这使得它在内存使用上比list(双向链表)更高效。

3.2 新增initializer_list构造


这点在先前列表初始化已经提到过,这是一个非常有用的提升与变化,initializer_list的引入使得 C++ 的初始化语法更加简洁、直观和灵活,提高了代码的可读性和可维护性。

3.3 新增移动构造、移动赋值和移动插入

这是非常重要的提升,可以大大提高效率。具体内容要等讲到右值引用和移动语义时会详细讲解。

3.4 其他

还比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。


真诚点赞,手有余香

这篇关于【C++练级之路】【Lv.21】C++11——列表初始化和声明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1004332

相关文章

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名