一:列表初始化
C++98中一般数组跟结构体可以用{}进行初始化

struct Point
{
     int _x;
     int _y;
};
int main()
{
    int array1[] = {1,2,3,4,5};
    int array2[] = {0};
    Point p = {1,2};
    return 0;
}

C++11中的{}
1.试图一切皆可用{}初始化,{}初始化也叫做列表初始化
2.内置类型支持,自定义类型也支持,自定义类型本质是类型转换,中间会产生临时对象,最后优化了以后变成直接构造
3.{}初始化的过程中,可以省略=
4.C++11列表初始化本意是想实现一个大统一的初始化方式,其次在一些场景下带来了不少的便利,例如容器push/list多参数构造的对象时,{}初始化会很方便

C++11中的std::initializer_list
1.本意是一个数组,内部有两个指针分别指向数组的开始和结束
2.也就是说支持迭代器遍历
3.容器支持一个std::initializer_list的构造函数,也就支持任意多个值构成的{x1,x2,x3…}进行初始化。STL中的任意容器支持任意多个值构成的{x1,x2,x3}进行初始化,也就是通过std::initializer_list的构造函数支持

二:右值引用和移动语义
1.C++98的语法中就有引用的语法
2.C++11中新增了右值引用语法特性
3.C++98学习的引用叫做左值引用
4.无论是左值引用还是右值引用,都是给对象取别名

上面是左值引用跟右值引用的介绍,那么再来介绍一下什么是左值,什么是右值
左值
1.变量名或解引用的指针,一般是持久状态,存储在内存中
2.可以获得它的地址
3.左值可以出现在赋值符号的左边,也可以在右边
4.定义const修饰后的左值,不能给他赋值,但是可以取它的地址

右值
1.要么是字面值常量
2.要么是表达式求值过程中创建的临时对象等
3.只能出现在赋值符号的右边
4.右值不能取地址

&10
&(x+y)
&string(""11111)

上面的都是错误写法,右值是不能取地址的

左值引用
Type& r1 = x;
1.就是给左值取别名
2.左值引用不能直接引用右值,但const左值引用可以引用右值
右值引用
Type&& rr1 = y;
1.就是给右值取别名
2.右值引用不能直接引用右值,但是右值引用可以引用move(左值)
move是库里面的一个函数模板,本质内部是进行强制类型转换,还涉及一些引用折叠

注意:变量表达式都是左值属性,也就意味着一个右值被右值引用绑定后,右值变量表达式的属性是左值

引用延长生命周期
右值引用可用于为临时对象延长生命周期,const的左值引用也能延长临时对象生存周期,但这些对象无法被修改

回顾左值引用的主要使用场景
1.函数中左值引用传参和左值引用传返回值时减少拷贝,同时还可以修改实参和修改返回对象的价值。
2.左值引用已经解决大多数场景的拷贝效率问题,但是有些场景不能使用传左值引用返回
3.当然右值引用返回也无法概念对象已经析构销毁的事实
就比如函数里面创建一了一个string对象,返回string对象时,string对象已经销毁,如果返回的是引用,那就变成野引用了,所以只能传值拷贝,如果是vector<vector>的传值拷贝,代价就太大了
在这里插入图片描述
所以就轮到移动构造和移动赋值登场了

移动构造
移动构造函数是⼀种构造函数,类似拷贝构造函数,移动构造函数要求第⼀个参数是该类类型的引用,但是不同的是要求这个参数是右值引用,如果还有其他参数,额外的参数必须有缺省值。

移动赋值
移动赋值是⼀个赋值运算符的重载,他跟拷贝赋值构成函数重载,类似拷贝赋值函数,移动赋值函数要求第⼀个参数是该类类型的引用,但是不同的是要求这个参数是右值引用。

作用
对于string/vector这样的深拷贝的类或者包含深拷贝的成员变量的类,移动构造跟移动赋值很有意义

右值引⽤和移动语义解决传值返回问题
在传值返回,如果是像vector这样深拷贝的类,传值返回不可避免,所以就可以传参的时候传临时对象,接受的形参也是右值引用,这样子还不能解决传值返回的问题,所以编译器进行了优化,就可以一步到位,直接构造,记得用场景一的写法,编译器才能一步到位的优化成直接构造,第二种场景太复杂了,先是用了默认构造初始化,然后又构造出一个临时对象,再进行移动构造,所以编译器不能直接构造
场景一:

int main()
{
bit::string ret = bit::addStrings("11111", "2222");
cout << ret.c_str() << endl;
return 0;
}

场景二:

int main()
{
bit::string ret;
ret = bit::addStrings("11111", "2222");
cout << ret.c_str() << endl;
return 0;
}

在这里插入图片描述
在这里插入图片描述
所以更推荐第一种写法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
赋值的也一样,就不多写了

右值引用和移动语义在传参中的提效
在这里插入图片描述
类型分类
右值划分为纯右值
move(x)后变为将亡值
泛左值包含左值跟将亡值

引用折叠
在这里插入图片描述
万能引用

template<class T>
void f(T&& x)
{}

由于引用折叠,传左值就是左值引用,传右值就是右值引用

完美转发
forward,是参数保持原来的属性,就比如传实参给参数是,虽然传的是右值,由于万能引用,弄出了右值引用接受了这个右值,但是形参那个变量的属性是左值,所以在函数内部在传递这个变量时,在变量前面加一个foeward,所以完美转发就是为了替万能引用服务的
在这里插入图片描述

三:可变参数模板
在这里插入图片描述
在这里插入图片描述

template<class ...Args>
void Print(Args&&... args)
{
	cout << sizeof...(args) << endl;
}

int main()
{
	double x = 2.2;
	Print();                       //包里0个参数
	Print(1);                      //包里1个参数
	Print(1,string("xxxx"));       //包里2个参数
	Print(1.1,string("xxxx"),x);   //包里3个参数
	return 0;
}

在这里插入图片描述
包扩展
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

// 本质可以理解为编译器编译时,包的扩展模式
// 将上面的函数模板扩展实例化为下面的函数
// 是不是很抽象,C++11以后,只能说委员会的大佬设计语法思维跳跃得太厉害

// void Print(int x, string y, double z)
// {
//     Arguments(GetArg(x), GetArg(y), GetArg(z));
// }

empalce系列接口
在这里插入图片描述
在这里插入图片描述

四:新的类功能
默认的移动构造和移动赋值
在这里插入图片描述
在这里插入图片描述

default跟delete
在这里插入图片描述

五:STL中的一些变化
在这里插入图片描述
在这里插入图片描述

六:lambda
在这里插入图片描述

int main()
{
	// 	⼀个简单	lambda	表达式

		auto add1 = [](int x, int y)->int {return x + y; };
	cout << add1(1, 2) << endl;
	// 1、捕捉为空也不能省略
		// 2、参数为空可以省略
		// 3、返回值可以省略,可以通过返回对象⾃动推导
		// 4、函数题不能省略
		auto func1 = []
		{
			cout << "hello bit" << endl;
			return 0;
		};
	func1();
	int a = 0, b = 1;
	auto swap1 = [](int& x, int& y)
		{
			int tmp = x;
			x = y;
			y = tmp;
		};
	swap1(a, b);
	cout << a << ":" << b << endl;
	return 0;
}

捕捉列表
在这里插入图片描述
在这里插入图片描述

auto func7 = [=]()mutable
    {
        a++;
        b++;
        c++;
        d++;
        return a + b + c + d;
    };

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
lambda的应用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

七:包装器
在这里插入图片描述
在这里插入图片描述

#include<functional>

int f(int a, int b)
{
	return a + b;
}

struct Functor
{
public:
	int operator()(int a, int b)
	{
		return a + b;
	}
};

class Plus
{
public:
	Plus(int n = 10)
		:_n(n)
	{ }

	static int plusi(int a, int b)
	{
		return a + b;
	}

	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}
private:
	int _n = 0;
};

int main()
{
	//包装各种可调用对象
	function<int(int, int)> f1 = f;
	function<int(int, int)> f2 = Functor();
	function<int(int, int)> f3 = [](int a, int b) {return a + b; };

	cout << f1(1, 1) << endl;
	cout << f2(1, 1) << endl;
	cout << f3(1, 1) << endl;

	//包装静态成员函数,在前面可加可不加&
	//成员函数要指定类域并且前面加&才能获取地址

	function<int(int, int)> f4 = &Plus::plusi;
	cout << f4(1, 1) << endl;

	//包装普通成员函数
	//普通成员函数还有一个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
	function<double(Plus*, double, double)> f5 = &Plus::plusd;
	Plus pd;
	cout << f5(&pd, 1.1, 1.1) << endl;

	function<double(Plus, double, double)> f6 = &Plus::plusd;
	cout << f6(pd, 1.1, 1.1) << endl;

	function<double(Plus&&, double, double)> f7 = &Plus::plusd;
	cout << f7(move(pd), 1.1, 1.1) << endl;
	cout << f7(Plus(), 1.1, 1.1) << endl;


	return 0;
}

在这里插入图片描述
这道题的新写法,不需要用switch case ,转为用map加上function

使用map映射string和function的方式实现

这种方式的最大优势之⼀是方便扩展,假设还有其他运算,我们增加map中的映射即可

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        map<string,function<int(int,int)>> mapo = {
            {"+",[](int x,int y){return (x+y);}},
            {"-",[](int x,int y){return (x-y);}},
            {"*",[](int x,int y){return (x*y);}},
            {"/",[](int x,int y){return (x/y);}}
        };
        
        for(auto& e: tokens)
        {
            if(mapo.count(e))
            {
                int right = _s.top();
                _s.pop();
                int left = _s.top();
                _s.pop();
                _s.push(mapo[e](left,right));

            }
            else
            {
                _s.push(stoi(e));
            }
        }
        return _s.top();
    }
private:
    stack<int> _s;
};

再来看看原来的写法

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> s;
        for(auto& e: tokens)
        {
            if(e=="+"||e=="-"||e=="*"||e=="/")
            {
                int right = s.top();
                s.pop();
                int left = s.top();
                s.pop();
                switch(e[0])
                {
                    case '+':
                    s.push(left+right);
                    break;
                    case '-':
                    s.push(left-right);
                    break;
                    case '*':
                    s.push(left*right);
                    break;
                    case '/':
                    s.push(left/right);
                    break;
                    default:
                    break;
                }

            }
            else
            {
                s.push(stoi(e));
            }
        }
        return s.top();
    }
};

bind
在这里插入图片描述
bind本质返回的一个仿函数对象
_1代表第一个形参
_2代表第二个形参
1.调用参数顺序(不常用)
2.调用参数个数(常用)
3.分别绑死第123个参数
4.成员函数对象进行绑死,就不需要每次都传递了

#include<functional>

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;

int Sub(int a, int b)
{
	return (a - b) * 10;
}

int SubX(int a, int b,int c)
{
	return (a - b - c) * 10;
}

class Plus
{
public:
	Plus(int n = 10)
		:_n(n)
	{ }

	static int plusi(int a, int b)
	{
		return a + b;
	}

	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}
private:
	int _n = 0;
};

int main()
{
	auto sub1 = bind(Sub, _1, _2);
	cout << sub1(10, 5) << endl;


	//bind本质返回的一个仿函数对象
	//调用参数顺序(不常用)
	//_1代表第一个形参
	//_2代表第二个形参
	auto sub2 = bind(Sub, _2, _1);
	cout << sub2(10, 5) << endl;

	//调用参数个数(常用)
	auto sub3 = bind(Sub, 100, _1);
	cout << sub3(5) << endl;

	auto sub4 = bind(Sub, _1, 100);
	cout << sub4(5) << endl;

	//分别绑死第123个参数
	auto sub5 = bind(SubX, 100,_1,_2);
	cout << sub5(5,1) << endl;

	auto sub6 = bind(SubX, _1,100,_2);
	cout << sub6(5,1) << endl;

	auto sub7 = bind(SubX, _1,_2,100);
	cout << sub7(5,1) << endl;

	//成员函数对象进行绑死,就不需要每次都传递了
	function<double(Plus&&, double, double)> f6 = &Plus::plusd;
	Plus pd;
	cout << f6(move(pd), 1.1, 1.1) << endl;
	cout << f6(Plus(), 1.1, 1.1) << endl;

	//上面的写法比较麻烦,所以用这种绑死一个参数,bind一般用于,绑死一些固定参数
	function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
	cout << f7(1.1, 1.1) << endl;

	//计算复利的lambda
	auto func1 = [](double rate, double money, int year)->double {
		double ret = money;
		for (int i = 0; i < year; i++)
		{
			ret += ret * rate;
		}
		return ret - money;
		};

	//绑死一些参数,实现出支持不同年华利率,不同金额和不同年份计算出复利的结算利息
	auto func3_1_5 = bind(func1, 0.015, _1, 3);
	auto func5_1_5 = bind(func1, 0.015, _1, 5);
	auto func10_2_5 = bind(func1, 0.025, _1, 10);
	auto func30_3_5 = bind(func1, 0.035, _1, 30);

	cout << func3_1_5(1000000) << endl;
	cout << func5_1_5(1000000) << endl;
	cout << func10_2_5(1000000) << endl;
	cout << func30_3_5(1000000) << endl;

	return 0;
}

更多推荐