您的位置:首页 > 新闻 > 热点要闻 > c++| c++11左右值引用,完美转发,可变参数模板

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

2024/10/13 15:50:15 来源:https://blog.csdn.net/2301_76180799/article/details/140831198  浏览:    关键词:c++| c++11左右值引用,完美转发,可变参数模板

c++| c++11的新特性

  • 左,右值引用
    • 什么是左值,右值
    • 左值引用和右值引用
    • 右值引用解决什么问题呢?
    • 移动构造
    • 万能引用
      • 形式
    • 完美转发
      • 格式
  • lambada表达式
    • 格式
  • 可变参数模板
    • 可变参数模板实现打印不同类型
    • emplace_push
    • 以list的emplace_back的实现举例

左,右值引用

什么是左值,右值

左右值的语法上的区别就是能不能取地址。
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 开销就很大

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

移动构造

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

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表达式

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_push

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

以list的emplace_back的实现举例

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com