赞
踩
左右值的语法上的区别就是能不能取地址。
int a = 10; a 可以取地址 是左值, 但是 10不能取地址 是右值。
常见的右值还有匿名对象,表达式返回值,字面常量(就是直接写出来的值比说刚刚的10)等。
左值引用 T &val , 右值应用 T&& val
一般的左值引用,只能引用只能引用左值,右值引用只能引用右值。
但是const & 可以引用右值
对于一个函数返回值不能用引用且拷贝开销很大的情况
。比如to_string 的返回值 就是string 不能是 &string 因为 它的生命周期只在函数内部。str 出了to_string 就销毁了。my::string s1 = my::to_string(123);
// 会经历 str 的构造,拷贝构造临时对象(深拷贝),赋值构造(深拷贝) s1 开销就很大
所以我们用移动构造优化它
就是 参数是右值引用的构造。
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;
}
大大节省了深拷贝的成本。
2.匿名对象直接当作函数的参数
string s1 = "hh";
vector<string> v;
v.push_back(s1);
//
v.push_back("hh");
上面的写法先构造s1,然后s1再拷贝构造给v中的data。
下面的写法是构造匿名对象,然后匿名对象直接移动构造给data,就不走深拷贝了。
值得注意的是右值引用本身的属性是左值的因为这样才能修改。左值有常属性。
template class<T &&>
void func(T && val)
{
....
}
与右值引用的区别就是上面带了个模板,我们传右值他就识别成右值,传左值它识别成左值
template class<T &&>
void func(T && val) //万能引用
{
do_something(forword<T>(val)); // 完美转发
}
完美转发常常和完美应用一起使用的,主要是防止右值引用的属性是左值,传给下一层被认为是左值了,从而走不到移动构造,移动拷贝等。
lambada表达式本质编译器帮我们生产了一个仿函数。
[]()-> return {} // -> 和return 可省 但是这[] 捕获列表不能省
//比如
[](int x, int y ) -> return (x+y;);
[=] 传值的方式捕获同一作用域的所有变量
[&]传引用的方式捕获同一作用域的所有变量
还可以混用比如[&,a,b]。 除了a,b 以外按转值捕获,其他按引用捕获。
template class<...Args>
void func(Args ...args)
{
}
// 编译时确定类型,所以要_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...); }
template <class T>
int printArg(T &t)
{
cout << t << " ";
return 0;
}
template <class ...Args>
void cpp_print(Args...args)
{
int arr[] = { printArg(args)... };
}
emplace_back 用的就是可变参数模板,在参数大于1的情况下,emplace_back 的效率比push_bakc更高。因为push_back 对于左值中间会走构造然后拷贝构造,对于右值会走构造,然后移动构造。
但是emplace_back 是直接传递的参数包,最后底层直接构造。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。