【C++11】右值引用和左值引用

1.{}的初始化设置

   1.1提出问题

当我们对于内置类型的初始化或者容器初始化,我们通常是需要自己先定义类型,然后for循环插入数据,这样写出来的代码,不够简洁,

C++11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围,使其可用于所有的内置类型和用户自定 义的类型,使用初始化列表时,可添加等号 (=) ,也可不添加 。如下面的例子
#include<iostream>
#include<vector>
#include<map>
using namespace std;
int main()
{
	// 内置类型变量
	int x1 = { 10 };
	int x2{ 10 };
	int x3 = 1 + 2;
	int x4 = { 1 + 2 };
	int x5{ 1 + 2 };
	// 数组
	int arr1[5]{ 1,2,3,4,5 };
	int arr2[]{ 1,2,3,4,5 };

	// 动态数组,在C++98中不支持
	int* arr3 = new int[5]{ 1,2,3,4,5 };

	// 标准容器
	vector<int> v{ 1,2,3,4,5 };
	map<string, int>dict1 = { pair<string,int>("sort",1),pair<string,int>("insert",2) };
	map<string, int>dict2 = { {"sort",1},{"insert",2} };
	map<int, int> m{ {1,1}, {2,2,},{3,3},{4,4} };
	return 0;
}

1.2 总结初始化列表

① 自定义支持->重写构造函数,一般是直接有的可以直接 调用

② 容器->C++11引入initializer_list,初始化列表,底层逻辑是迭代器加push_back支持。

#include <initializer_list>
template<class T>
class Vector {
public:
	// ... 
	Vector(initializer_list<T> l) : _capacity(l.size()), _size(0)
	{
		_array = new T[_capacity];
		for (auto e : l)
			_array[_size++] = e;//这里跟迭代器加尾插的思想一样
	}

	Vector<T>& operator=(initializer_list<T> l) {
		delete[] _array;
		size_t i = 0;
		for (auto e : l)
			_array[i++] = e;
		return *this;
	}
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};

 2 变量类型推导auto与范围for

早期的auto只是用来表示变量的自动化创建和销毁,但是在C++11中用来表示类型推导,这个提出来的目的主要是解决,迭代器类型过长的问题。

#include<iostream>
#include<map>
int main(){
	std::map<std::string, std::string> m{ {"apple", "苹果"}, {"banana","香蕉"} };
// 使用迭代器遍历容器, 迭代器类型太繁琐
//std::map<std::string, std::string>::iterator it = m.begin();
	auto it = m.begin();
	while (it != m.end())
	{
		std::cout << it->first << " " << it->second << std::endl;
		++it;
	}
return 0;
}

但是,auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。我们注意一个问题,当在表达式或者返回值,需要编译运行,才能知道的类型,auto就显得无能为力,这个时候就需要使用decltype

void* GetMemory(size_t size)
{
	return malloc(size);
}
int main()
{
	int a = 10;
	int b = 20;

	// 用decltype推演a+b的实际类型,作为定义c的类型
	decltype(a + b) c;
	cout << typeid(c).name() << endl;
	// 如果没有带参数,推导函数的类型
	cout << typeid(decltype(GetMemory)).name() << endl;

	// 如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,不会执行函数
	cout << typeid(decltype(GetMemory(0))).name() << endl;

	return 0;
}

3. nullptr 与智能指针

 在C++11中,为了区别0和空指针,提出了nullptr,出于安全考虑

4.STL中的变化

①增加新容器

②针对旧容器,基本增加了移动构造,移动赋值,所有的插入接口函数,都增加了右值引用的版本,用来提高效率。

5.左值和右值

左值可以获取地址+可以赋值。const修饰的左值只能取地址

左值引用:给左值区别,只能引用左值,不能引用右值,但是const左值引用可以引用左值也可以引用右值。

主要应用场景:void push_back(const T&x),这里传参实参既可以是左值也可以是右值。

右值: 不能出现在赋值符号的左边,也就是不能修改,也不能取地址。只能出现在右边

int main()
{
	//左值
	int* p = new int(0);
	int b = 1;
	const int c = 2;
	//左值引用
	int*& rp = p;
	int& rb = b;
	const int& rc = c;
	int& pvalue = *p;

	//常见右值
	10;
	double x = 1.1, double y = 2.2;
	x + y;
	fmin(x + y);
	//右值引用
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);

	return 0;
}

右值引用:右值不能取地址,但是右值引用会将右值存到特定的位置,取到该地址的位置。也可以修改。加个const就不能修改右值引用。

只能引用右值,不能引用左值。非要用呢?移动语义 int&& rr1=std::move(a);

5.1使用场景

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值