C++从零开始(day55)——C++11

这是关于一个普通双非本科大一学生的C++的学习记录贴

在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料

那么开启正题

今天分享的是关于C++的语法知识点

1.列表初始化

在C++11中扩大了花括号的括起的初始化列表的使用范围,使用初始化列表时可以使用=也可以不使用

void Test1()
{
	vector<int> v1{ 2,6,23,1,6,4 };
	vector<int> v2 = { 2,6,23,1,6,4 };

	string s{ "hello" };

	int x1 = 1;
	int x2{ 2 };
}

这个语法了解即可,不常用

这里还涉及到initializer_list,它一般作为构造函数的参数,使初始化容器更加方便

2.声明

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

2.1auto

auto我们已经很熟悉了,它可以自动识别类型,增强代码可读性

注意:auto不能作为函数参数列表以及返回值的类型

2.2decltye

我们知道typeid可以返回一个数据的类型

void Test2()
{
	int a;
	cout << typeid(a).name() << endl;
	cout << typeid(string).name() << endl;
}

但是如果我们想利用一个已知数据,创建一个与其相同类型的数据,typeid还是无法做到,因此C++11引入了decltye关键字,可以完成这个任务

void Test3()
{
	int x = 1;
	double y = 3.14;

	decltype(x * y) a;
	decltype(&x) b;

	cout << typeid(a).name() << endl;
	cout << typeid(b).name() << endl;
}

2.3nullptr

在C语言中空指针是NULL,实质上他是由0定义而来的,很显然这不够严谨,于是C++11引入了nullptr,他是由(void*)0定义而来的

#define 0 NULL
#define (void*)0 nullptr

3.范围for

这个我们已经很熟悉了,这里不展开说了,简单回顾一下,范围for会被编译器转化为迭代器,所以支持迭代器就支持范围for,这也是queue,stack不支持范围for的原因

4.新容器

array:定长数组,实际中并不常用,这里不做详细展开

forward_list:单链表,实际中并不常用,这里不做详细展开

void Test4()
{
	array<int, 100> arr = { 1,2,4, };
	forward_list<int> fl = { 3,5,6,2 };
}

unordered_set,unordered_map

哈希表实现的set,map,因为比map,set效率高,是我们常用,也是需要重点掌握的容器,由于刚学完这块内容,也不过多介绍了

5.右值引用与移动语义

5.1左值引用与右值引用

前面我们学过左值引用,他是为已经开辟空间的对象再取一个别名,右值引用实质上也是对对象取别名,但是它们操作的场景不同

我们先来思考一下,什么是左值,什么是右值

可以修改的可以认为是左值,左值一般是变量

右值通常是常量,表达式或者函数返回值(临时对象)

void Test5()
{
	int a = 0;
	int& b = a;

	int&& c = 0;
}

左值引用右值引用的定义如上

5.2左值引用右值引用比较

左值引用:左值引用只能引用左值,加上const后才能引用右值

右值引用:右值引用只能引用右值,但可以引用move后的左值

void Test6()
{
	int a = 0;
	int& b = a;

	//int& c = 0; // err
	const int& c = 0;

	int&& x = 0;
	int y = 0;
	//int&& z = y; //err
	int&& z = move(y);

}

5.3右值引用的意义

通过上面的例子我们好像看不出来右值引用的意义,而左值引用的意义我们熟悉,减少不必要的深拷贝,提高效率,右值引用的意义到底是什么呢?

右值引用引用的对象右值,我们得对右值下文章

右值可以像以下这样分类

纯右值:基本类型的常量或临时对象

将亡值:自定义类型的临时对象

我们的右值引用就是对将亡值下文章的

我们来看以下情景

void Test7()
{
	string s1("hello");

	string s2(string("world"));
}

如果我们用一个临时对象对s2初始化,(不考虑编译器优化)那么会先创建一个临时匿名对象,再深拷贝给s2,再析构临时匿名对象,这里很明显消耗了不必要的效率,如果我们将临时匿名对象的_str与s2的交换,就不用深拷贝了,而用右值引用(与左值引用的拷贝构造 构成重载)我们就可以检测到并且节省效率

string& string(const string& s)
{
	//...
}

string& string(string&& s)
{
	swap(_str, s._str);
	return *this;
}

我们把这里的构造叫做移动构造,实际运用中,不仅仅有移动构造,还有移动赋值

前面我们说到,右值引用可以引用move后的左值,实际上,他会强制将左值转化为右值,实现移动语义

新手写博客,有不对的位置希望大佬们能够指出,也谢谢大家能看到这里,让我们一起学习进步吧!

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值