当前位置:   article > 正文

c++| c++11左右值引用,完美转发,可变参数模板

c++| c++11左右值引用,完美转发,可变参数模板

左,右值引用

什么是左值,右值

左右值的语法上的区别就是能不能取地址。
int a = 10; a 可以取地址 是左值, 但是 10不能取地址 是右值。
常见的右值还有匿名对象,表达式返回值,字面常量(就是直接写出来的值比说刚刚的10)等。

左值引用和右值引用

左值引用 T &val , 右值应用 T&& val
一般的左值引用,只能引用只能引用左值,右值引用只能引用右值。
但是const & 可以引用右值

右值引用解决什么问题呢?

  1. 对于一个函数返回值不能用引用且拷贝开销很大的情况。比如to_string 的返回值 就是string 不能是 &string 因为 它的生命周期只在函数内部。str 出了to_string 就销毁了。

在这里插入图片描述

my::string s1 = my::to_string(123);
// 会经历 str 的构造,拷贝构造临时对象(深拷贝),赋值构造(深拷贝) s1 开销就很大
  • 1
  • 2

所以我们用移动构造优化它

移动构造

就是 参数是右值引用的构造。

string(string&& s)
	:_str(nullptr)
{
	cout << "string(string&& s) -- 移动构造" << endl;
	swap(s);
}

// 移动赋值
string& operator=(string&& s)
{
	cout << "string(string&& s) -- 移动赋值" << endl;
	swap(s);

	return *this;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述
大大节省了深拷贝的成本。
2.匿名对象直接当作函数的参数

string s1 = "hh";
vector<string> v;
v.push_back(s1);

//
v.push_back("hh");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上面的写法先构造s1,然后s1再拷贝构造给v中的data。
下面的写法是构造匿名对象,然后匿名对象直接移动构造给data,就不走深拷贝了。

值得注意的是右值引用本身的属性是左值的因为这样才能修改。左值有常属性。

万能引用

形式

template class<T &&>
void func(T && val)
{
	....	
}
  • 1
  • 2
  • 3
  • 4
  • 5

与右值引用的区别就是上面带了个模板,我们传右值他就识别成右值,传左值它识别成左值

完美转发

格式

template class<T &&>
void func(T && val) //万能引用
{
	do_something(forword<T>(val)); // 完美转发
}
  • 1
  • 2
  • 3
  • 4
  • 5

完美转发常常和完美应用一起使用的,主要是防止右值引用的属性是左值,传给下一层被认为是左值了,从而走不到移动构造,移动拷贝等。

lambada表达式

lambada表达式本质编译器帮我们生产了一个仿函数。

格式

[]()-> return {} // -> 和return 可省 但是这[] 捕获列表不能省 
//比如
[](int x, int y ) -> return (x+y;);
  • 1
  • 2
  • 3

[=] 传值的方式捕获同一作用域的所有变量
[&]传引用的方式捕获同一作用域的所有变量
还可以混用比如[&,a,b]。 除了a,b 以外按转值捕获,其他按引用捕获。

可变参数模板

template class<...Args>
void func(Args ...args)
{

}
  • 1
  • 2
  • 3
  • 4
  • 5

可变参数模板实现打印不同类型

// 编译时确定类型,所以要_cpp_print() 递归到最后,参数为空。
void _cpp_print() 
{

}
template<class T,class ... Args>
void _cpp_print(T & val, Args ...args)
{
	cout << val << " ";
	_cpp_print(args...);
}

template <class ...Args >
void cpp_print(Args... args)
{
	_cpp_print(args...);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

template <class T>
int printArg(T &t)
{
	cout << t << " ";
	return 0;
}

template <class ...Args>
void cpp_print(Args...args)
{
	int arr[] = { printArg(args)... };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

emplace_push

在这里插入图片描述
emplace_back 用的就是可变参数模板,在参数大于1的情况下,emplace_back 的效率比push_bakc更高。因为push_back 对于左值中间会走构造然后拷贝构造,对于右值会走构造,然后移动构造。
但是emplace_back 是直接传递的参数包,最后底层直接构造。

以list的emplace_back的实现举例

在这里插入图片描述

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号