DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

左值(lvalue)与右值(rvalue)

左值与右值的概念其实在C++0x中就有了。概括的讲,凡是能够取地址的可以称之为左值,反之称之为右值,C++中并没有对左值和右值给出明确的定义,从其解决手段来看类似上面的定义,当然我们还可以定义为:有名字的对象为左值,没有名字的对象为右值。

 
 
class A
 
{};
 
1
 
2
 
A a; // a为左值,因为其有明确名字,且对a进行 &a 是合法的。
 
 
 
void Test(A a)
 
{
 
__Test(a);
 
}
 
 
 
Test(A()); // A() 为右值,因为A()产生一个临时对象,临时对象没有名字且无法进行 &取址操作。
 
 
 
对 __Test(a); 而言,这里的a为左值,因为这里的a对调用方而言是具名的,
 
__Test内部对a也是可以进行 &取址操作的。
 
但这个a在调用完毕后很快被销毁,毕竟它只是一个临时变量。
 
 
 
所以从上述的伪代码中还可以知道:因为函数内的嵌套调用,
 
上一层的右值是可以“变成”左值以完成下层调用,意即:可以接受右值的右值引用本身却是个左值
 
 

(https://blog.csdn.net/hejjunlin/article/details/78104719)

 

移动语义(std::move)

 在C++11中,标准库在<utility>中提供了一个有用的函数std::move,std::move并不移动任何对象与数据,它的功能是将一个左值或者右值强制转化为右值引用,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue)。

td::move解决效率问题,减少不必要的拷贝:A对象可以根据右值引用知道传入的是一个临时的对象B,把临时对象B中的堆内存数据(可能是大数据块)直接使用而不重新分配内存,再把临时对象B对应指针置空,实现数据移动(move之后B对象不能再使用)。减少了A重新分配内存与数据拷贝的消耗以及临时对象B进行数据销毁的消耗。

 
 
class Test
 
{
 
public:
 
Test() :array(nullptr)
 
{
 
}
 
 
 
~Test()
 
{
 
if(nullptr != array)
 
{
 
delete [] array;
 
array = nullptr;
 
}
 
}
 
 
 
Test(Test &&other)
 
{
 
this->array = other.array;
 
other.array = nullptr;
 
}
 
 
 
Test& operator = (Test &&other)
 
{
 
//do some operate...
 
this->array = other.array;
 
other.array = nullptr;
 
return *this;
 
}
 
 
 
private:
 
int *array;//指向一个很大的数组
 
};
 
 
 
 
 
Test B;
 
//do some thing to B.array
 
Test A(std::move(B));
 
 

完美转发(std::forward)

当我们将一个右值引用传入函数时,他在实参中有了命名,所以继续往下传或者调用其他函数时,根据C++ 标准的定义,这个参数变成了一个左值。那么他永远不会调用接下来函数的右值版本,这可能在一些情况下造成拷贝。为了解决这个问题 C++ 11引入了完美转发,根据右值判断的推倒,调用forward 传出的值,若原来是一个右值,那么他转出来就是一个右值,否则为一个左值。
这样的处理就完美的转发了原有参数的左右值属性,不会造成一些不必要的拷贝。

 
 
#include <iostream>
 
#include <vector>
 
#include <string>
 
 
 
using namespace std;
 
 
 
int main()
 
{
 
string A("abc");
 
string&& Rval = std::move(A);
 
string B(Rval); // this is a copy , not move.
 
cout << A << endl; // output "abc"
 
string C(std::forward<string>(Rval)); // move.
 
cout << A << endl; /* output "" */
 
return 0;
 
}
 
 

(https://blog.csdn.net/coolwriter/article/details/80970718)

 

std::ref和std::cref

https://blog.csdn.net/lmb1612977696/article/details/81543802

 

 
posted on   DoubleLi  阅读(183)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2014-03-16 source code analyzer 功能强大的C/C++源代码分析软件 Celerity CRACK 破解版
2014-03-16 分析函数调用关系图(call graph)的几种方法
2014-03-16 用CodeViz绘制函数调用关系图(call graph)
2014-03-16 C++的辅助工具介绍
2013-03-16 位运算中的异或运算 .
2013-03-16 按位与、或、异或等运算方法
2012-03-16 Javascript 对象用法
点击右上角即可分享
微信分享提示