栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++左值,右值以及消亡值

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++左值,右值以及消亡值

1.左值和右值

C++11中的定义:左值表达式表示的是一个对象的身份(在内存中的位置),而右值表达式表示的是对象的值(内容)。

  • 左值和右值都是针对表达式而言的,左值是持久的,右值是短暂的:左值在表达式结束后仍然存在,右值在表达式结束后会被销毁。
  • 区分左值和右值的方法:看能不能进行取地址操作,若能,则为左值,否则为右值。
1.1右值:
void fun(int &x) {
//
}

int main() {
  fun(10);
  return 0;
}

编译的时候提示:

error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’

报错的rvalue就是10,(右值的一个特性,无法取址)

1.2左值
void fun(int &x) {
//
}

int main() {
  int x=10;
  fun(x);
  return 0;
}

这样x就是左值了。

注意:在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。

1.3消亡值

**prvalue右值引用(&&),**用于计算的或者用于初始化对象的,p代表的是Pure。
lvalue左值可被取址,指在内存中具有位置的值。
那么消亡值,xvalue又是什么?
**xvalue 就是临时变量(temporary object)。**它是快要被销毁的值,x 代表expiring,所以可以被重新使用。
常见的xvalue有:由prvalue实体化创建的临时变量,函数内的局部变量被return的时候(在它生命的最后时刻);std::move修饰的表达式;返回类型为T&&的函数的调用, T&& f()。

1.4总结:

每一类值对应不同的构造方法:

prvalue初始化lvalue,是直接构建,不用调用拷贝或移动构造函数;
xvalue初始化lvalue,会调用移动函数,也就是move;
lvalue初始化lvalue,会调用拷贝构造函数。

  • xvalue可以被直接move;
  • prvalue被move的时候,可以理解生成了一个临时变量xvalue,这个临时变量xvalue被move了;
  • 如果move lvalue,那么需要使用std::move将lvalue变成xvalue,从而move生成后的xvalue。

移动语义

  • C++11标准引入了“对象移动”的概念
  • 对象移动的特性是:可以移动而非拷贝对象
  • 在C++旧标准中,没有直接的方法移动对象。因此会有很多不必要的资源拷贝。
    一个例子(移动拷贝构造):我放风筝,有人想玩风筝,我直接把风筝线交给这个人。风筝在空中,一直没有被移动,但所有权已经从我手中交给另一个人。这就是move。
    move:原使用对象不再使用,直接转接对象的所有权。

example:

int gI = 0;
class Book {
public:
  int m{3};
  Book() {
    std::cout << gI << ":"
              << "default constructorn";
  }
  Book(Book &&b) {
    std::cout << gI << ":"
              << "move constructorn";
  }
  Book(const Book &b) {
    std::cout << gI << ":"
              << "copy constructorn";
  }
  Book &operator=(const Book &) {
    std::cout << gI << ":"
              << "copy assigmentn";
              return *this;
  }
  Book &operator=(Book &&) {
    std::cout << gI << ":"
              << "move assignmentn";
              return *this;
  }
};
int main() {
  std::cout<<"-------"< 

输出:

-------
0-0:default constructor
1-1:default constructor
2-2:default constructor
2:move assignment
3-3:move assignment

另外要注意的是,右值引用是对rvalue的引用,但是这个引用却是lvalue,所以下面的代码如果要调用T类型的移动函数,要这么写,

void f(T&& v) {
  T v = std::move(v); //要调用移动函数,但是v是lvaue,所以我们要使用std::move
} 

理解的关键是,右值引用是一个类型,而v是一个变量,所以是左值——一个引用了右值的左值变量。所以我们需要在前面加上std::move。

std::string s =" hell world";
auto left = std::move(s);
cout< 

s已经是空值了,不建议再使用s这个变量

所以,C++的move改变了值的所有权

2.move的使用: 1.接管资源
void My::take(Book && iBook) 
{
  mBook = std::move(iBook); //将没人要的iBook,拿过来据为己有
}
2.转移所有权
auto thread = std::thread([]{});
std::vector lThreadPool;
lThreadPool.push_back(std::move(thread)); //现在thread pool来掌控着thread
3.避免拷贝
void f() {
  std::vector v = ...;
  take(std::move(v)); // 直接move进了函数g里面,不用拷贝
}

参考资料:
move

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869608.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号