首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++11(1)

C++11(1)

作者头像
啊QQQQQ
发布2024-11-19 19:15:59
发布2024-11-19 19:15:59
2350
举报
文章被收录于专栏:C++C++

前言

小故事

1998 年是 C++ 标准委员会成立的第一年,本来计划以后每 5 年视实际需要更新一次标准, C++ 国际

标准委员会在研究 C++ 03 的下一个版本的时候,一开始计划是 2007 年发布,所以最初这个标准叫

C++ 07 。但是到 06 年的时候,官方觉得 2007 年肯定完不成 C++ 07 ,而且官方觉得 2008 年可能也

完不成。最后干脆叫 C++ 0x 。 x 的意思是不知道到底能在 07 还是 08 还是 09 年完成。结果 2010 年的

时候也没完成,最后在 2011 年终于完成了 C++ 标准。所以最终定名为 C++11 。

C++11优势

C++11是继1998年的后更新的C++大版本;C++11对比C++98带来了数量可观的变化,增加了很多新特性。相比较而言C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多。所以对C++11的学习是很重要的。

这里是C++11的具体内容C++11 - cppreference.com,有兴趣的可以看看;

统一的列表初始化

1.{}初始化

在 C++98 中,标准允许使用花括号 {} 对数组或者结构体元素进行统一的列表初始值设定。比如:

创建对象时也可以使用列表初始化方式调用构造函数初始化;

代码语言:javascript
复制
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}

C++11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围,使其可用于所有的内置类型和用户自

定义的类型, 使用初始化列表时,可添加等号 (=) ,也可不添加

代码语言:javascript
复制
struct Point
{
 int _x;
 int _y;
};
int main()
{
 int x1 = 1;
 int x2{ 2 };
 int array1[]{ 1, 2, 3, 4, 5 };
 int array2[5]{ 0 };
 Point p{ 1, 2 };
 // C++11中列表初始化也可以适用于new表达式中
 int* pa = new int[4]{ 0 };
 return 0;
}

创建对象时也可以使用列表初始化方式调用构造函数初始化

代码语言:javascript
复制
class Date
{
public:
 Date(int year, int month, int day)
 :_year(year)
 ,_month(month)
 ,_day(day)
 {
 cout << "Date(int year, int month, int day)" << endl;
 }
private:
 int _year;
 int _month;
 int _day;
};
int main()
{
 Date d1(2022, 1, 1); // old style
 // C++11支持的列表初始化,这里会调用构造函数初始化
 Date d2{ 2022, 1, 2 };
 Date d3 = { 2022, 1, 3 };
 return 0;
}

C++支持一切即可列表初始化,并且可以省略赋值符号;

2. std::initializer_list

小问题:date d={2024,9,4};和vector<int>v={2024,7,25};的{}有什么区别?

这两个{}本质上是不一样的,date d的{}会调用它的构造函数初始化d,而date类中只有三个参数,所以{}中只能有3个数;但是vector就不一样了,vector的{}中的元素数量是可变化的,并不是固定的三个;同样其他的容器list等也是如此;因此传递的参数是一个数组来进行初始化;为了方便统一,所以就出现了initializer_list的数组容器来统一作为数组参数;

std::initializer_list的介绍文档: https://cplusplus.com/reference/initializer_list/initializer_list/

在vector和list的底层实现拷贝构造时也使用到了initializer_list当参数来接收数组;我们可以使用列表模拟一个数组来看下其类型;

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>

using namespace std;



int main()
{
	auto it = { 1,2,3 };//it就是initializer_list的类型的
	cout << typeid(it).name() << endl;       
	return 0;
}

我们会发现数组的类型就是initializer_list而且是个模版;因此我们可以把initializer_list看成是一个{}形式的数组容器;

那么initializer_list底层到底是什么呢?

其实initializer_list是一个容器;这个容器包含了两个指针;一个指向数组的头部,一个指向数组的尾部; 然后还提供了迭代器操作;我们可以来验证一下;

我们从调试中可以看出的确是包含了两个指针,分别指向数组的头和尾,而且提供了迭代器操作;另外我创建了一个局部变量,我们都知道局部变量是创建在栈上的,通过对比数组的地址和局部变量的地址我们可以推断出initializer_list是在栈上开辟的数组;

{}和initializer_list的优势体现:

例子:

代码语言:javascript
复制
	map <string, string >mp = { {"apple","苹果"},{"banana","香蕉"},{"sort","排序"} };

分析:这个mp初始化使用了{}和initializer_list的结合;{"apple","苹果"}等是调用了pair<string ,string>的构造函数,最外层就是initializer_list;整体来看就是个pair<string,string>类型的数组;这样的好处就是不需要多次的创造pair<string,string>的临时变量进行初始化,极大的方便了c++玩家;

声明

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

1.auto

auto 可以自动的推导变量的类型,一般用于替代代码较长的类型或范围for循环中; 需要注意的是auto 后不可以用于函数参数或者返回类型;

代码语言:javascript
复制
int main()
{
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
return 0;
}

2.decltype

代码语言:javascript
复制
// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
decltype(t1 * t2) ret;
cout << typeid(ret).name() << endl;
}
int main()
{
const int x = 1;
double y = 2.2;
decltype(x * y) ret; // ret的类型是double
decltype(&x) p;      // p的类型是int*
cout << typeid(ret).name() << endl;
cout << typeid(p).name() << endl;
F(1, 'a');
return 0;
}

decltype也可以推导出变量的类型,但是与typeid不同的是他可以作为类型本身来使用;而typeid只能以字符串的形式打印出来;相比之下decltype更加的灵活;

3.nullptr

由于 C 中 NULL 被定义成字面量 0 ,这样就可能回带来一些问题,因为 0 既能指针常量,又能表示

整形常量。所以出于清晰和安全的角度考虑, C++11 中新增了 nullptr ,用于表示空指针。

代码语言:javascript
复制
#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

C中的问题:这是在C++文件中的一段代码,两个函数的参数分别是int和int*,当实参是NULL时是可以调用第一个函数的,因为C中define了NULL是0;如果要调用第二个函数是不是就需要传实参为指针类型,我们就需要传参数((void*)0);这个在C中发生类型转换把0转换为int*的;但是在C++中是不支持void*转换的;所以就出现了问题;因此C++中支持nullptr为空指针;

今天的文章到这里就结束啦,我后续会继续补充的;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 小故事
    • C++11优势
  • 统一的列表初始化
    • 1.{}初始化
    • 2. std::initializer_list
  • 声明
    • 1.auto
    • 2.decltype
    • 3.nullptr
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档