1. 它是什么?
  2. 它有什么作用?
  3. 什么时候应该使用?

赞赏良好的链接。


#1楼

当您需要在其他地方“传输”对象的内容时,可以使用move,而无需复制(即内容不重复,这就是为什么它可以用于某些不可复制的对象,如unique_ptr)。 使用std :: move,对象也可以在不进行复制(并节省大量时间)的情况下获取临时对象的内容。

这个链接真的帮助了我:

http://thbecker.net/articles/rvalue_references/section_01.html

如果我的答案来得太晚,我很抱歉,但我也在寻找std :: move的良好链接,我发现上面的链接有点“严肃”。

这强调了r值参考,在哪种情况下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。


#2楼

std :: move本身并没有做太多。 我认为它为一个对象调用了移动的构造函数,但它实际上只是执行一个类型转换(将一个左值变量转换为一个rvalue,以便所述变量可以作为参数传递给一个移动构造函数或赋值运算符)。

因此std :: move仅用作使用移动语义的前兆。 移动语义本质上是处理临时对象的有效方式。

考虑对象A = B + C + D + E + F;

这是漂亮的代码,但E + F产生一个临时对象。 然后D + temp产生另一个临时对象,依此类推。 在类的每个普通“+”运算符中,都会出现深拷贝。

例如

Object Object::operator+ (const Object& rhs) {Object temp (*this);// logic for addingreturn temp;
}

在此函数中创建临时对象是无用的 - 当这些临时对象超出范围时,它们将在行尾删除。

我们宁愿使用移动语义来“掠夺”临时对象并执行类似的操作

 Object& Object::operator+ (Object&& rhs) {// logic to modify rhs directlyreturn rhs;}

这避免了不必要的深拷贝。 参考该示例,发生深度复制的唯一部分现在是E + F.其余部分使用移动语义。 还需要实现移动构造函数或赋值运算符以将结果分配给A.


#3楼

“它是什么?”

虽然std::move()在技​​术上是一个函数 - 我会说它不是一个真正的函数 。 它是编译器考虑表达式值的方式之间的转换器。

“它做了什么?”

首先要注意的是std::move() 实际上并没有移动任何东西 。 它将表达式从左值 (例如命名变量)转换为x值 。 xvalue告诉编译器:

你可以掠夺我, 移动任何我持有的东西并在其他地方使用它(因为我很快就会被摧毁)“。

换句话说,当你使用std::move(x) ,你允许编译器蚕食x 。 因此,如果x在内存中有自己的缓冲区 - 在std::move() ,编译器可以让另一个对象拥有它。

你也可以从一个prvalue (例如你正在传递的临时值)移动,但这很少有用。

“什么时候应该使用?”

提出这个问题的另一种方法是“我会将现有对象的资源用于什么?” 好吧,如果您正在编写应用程序代码,那么您可能不会对编译器创建的临时对象进行大量处理。 因此,主要是在构造函数,运算符方法,类似标准库算法等函数的地方执行此操作,其中对象自动创建和销毁很多。 当然,这只是一个经验法则。

典型的用法是将资源从一个对象“移动”到另一个对象而不是复制。 @Guillaume链接到此页面 ,其中有一个简单的简短示例:使用较少的复制交换两个对象。

template <class T>
swap(T& a, T& b) {T tmp(a);   // we now have two copies of aa = b;      // we now have two copies of b (+ discarded a copy of a)b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

使用move允许您交换资源而不是复制它们:

template <class T>
swap(T& a, T& b) {T tmp(std::move(a));a = std::move(b);   b = std::move(tmp);
}

想想当T是大小为n的vector<int>时会发生什么。 在第一个版本中,您读取和写入3 * n个元素,在第二个版本中,您基本上只读取和写入向量缓冲区的3个指针。 当然,T级需要知道如何进行移动; 你的类应该有一个移动赋值运算符和一个T类的移动构造函数,以便它可以工作。


#4楼

关于C ++ 11 R值参考和移动构造函数的Wikipedia页面

  1. 在C ++ 11中,除了复制构造函数之外,对象还可以有移动构造函数。
    (除了复制赋值运算符,它们还有移动赋值运算符。)
  2. 如果对象具有类型“rvalue-reference”( Type && ),则使用移动构造函数而不是复制构造函数。
  3. std::move()是一个转换器,它生成对象的rvalue引用,以便从中移动。

这是一种避免复制的新C ++方法。 例如,使用移动构造函数, std::vector可以将其内部指针复制到新对象,使移动的对象保持不正确状态,从而避免复制所有数据。 这将是C ++ - 有效。

尝试谷歌搜索移动语义,右值,完美转发。


#5楼

问:什么是std::move

答: std::move()是C ++标准库中用于转换为右值引用的函数。

简单地说std::move(t)相当于:

static_cast<T&&>(t);

rvalue是一个临时值,它不会超出定义它的表达式,例如从不存储在变量中的中间函数结果。

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

在N2027中给出了std :: move()的实现:“Rvalue References简介”如下:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{return a;
}

如您所见,无论是否使用值( T ),引用类型( T& )或右值引用( T&& )调用, std::move返回T&&

问:它有什么作用?

答:作为演员,它在运行时没有做任何事情。 只有在编译时才能告诉编译器您希望继续将引用视为右值。

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

没有做什么:

  • 复制参数
  • 调用复制构造函数
  • 更改参数对象

问:什么时候应该使用?

答:如果要调用支持移动语义的函数,并且参数不是rvalue(临时表达式),则应该使用std::move

这为我提出了以下后续问题:

  • 什么是移动语义? 与复制语义相比,移动语义是一种编程技术,其中通过“接管”而不是复制另一个对象的成员来初始化对象的成员。 这种“接管”只能通过指针和资源句柄来实现,这可以通过复制指针或整数句柄而不是底层数据来便宜地转移。

  • 什么样的类和对象支持移动语义? 作为开发人员,您可以在自己的类中实现移动语义,如果这些将从传输其成员而不是复制它们中受益。 一旦实现了移动语义,您将直接受益于许多库程序员的工作,他们已经添加了对有效处理具有移动语义的类的支持。

  • 为什么编译器不能自己搞清楚? 除非你这样说,否则编译器不能只调用函数的另一个重载。 您必须帮助编译器选择是否应该调用常规或移动版本的函数。

  • 在哪种情况下,我想告诉编译器它应该将变量视为右值? 这很可能发生在模板或库函数中,您知道可以挽救中间结果。


#6楼

“它是什么?”“它做了什么?” 已在上面解释过。

我将举例说明“应该何时使用”。

例如,我们有一个包含大数组资源的类。

class ResHeavy{ //  ResHeavy means heavy resourcepublic:ResHeavy(int len=10):_upInt(new int[len]),_len(len){cout<<"default ctor"<<endl;}ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){cout<<"copy ctor"<<endl;}ResHeavy& operator=(const ResHeavy& rhs){_upInt.reset(new int[rhs._len]);_len = rhs._len;cout<<"operator= ctor"<<endl;}ResHeavy(ResHeavy&& rhs){_upInt = std::move(rhs._upInt);_len = rhs._len;rhs._len = 0;cout<<"move ctor"<<endl;}// check array validbool is_up_valid(){return _upInt != nullptr;}private:std::unique_ptr<int[]> _upInt; // heavy array resourceint _len; // length of int array
};

测试代码:

void test_std_move2(){ResHeavy rh; // only one int[]// operator rh// after some operator of rh, it becomes no-use// transform it to other objectResHeavy rh2 = std::move(rh); // rh becomes invalid// show rh, rh2 it validif(rh.is_up_valid())cout<<"rh valid"<<endl;elsecout<<"rh invalid"<<endl;if(rh2.is_up_valid())cout<<"rh2 valid"<<endl;elsecout<<"rh2 invalid"<<endl;// new ResHeavy object, created by copy ctorResHeavy rh3(rh2);  // two copy of int[]if(rh3.is_up_valid())cout<<"rh3 valid"<<endl;elsecout<<"rh3 invalid"<<endl;
}

输出如下:

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

我们可以看到std::move with move constructor很容易实现转换资源。

还有什么地方std::move有用吗?

在对元素数组进行排序时, std::move也很有用。 许多排序算法(例如选择排序和冒泡排序)通过交换元素对来工作。 以前,我们不得不求助于复制语义来进行交换。 现在我们可以使用移动语义,这更有效。

如果我们想将一个智能指针管理的内容移动到另一个智能指针,它也会很有用。

引:

  • https://www.learncpp.com/cpp-tutorial/15-4-stdmove/

什么是std :: move(),什么时候应该使用?相关推荐

  1. C++右值引用 和 std::move()

    void debug(int&& a){return a; } std::move(a) 可以将左值变为右值 int c = 0x100; // c 可以被取地址,c 为左值,c++ ...

  2. 43.StrVec类:std::move调用移动构造函数的一个实例

    自定义一个strvec类,在内存不够,开辟新的内存存放元素的时候(也即是reallocate),使用移动操作!而非拷贝! using namespace std;class strvec { priv ...

  3. C++ Primer 5th笔记(chap 16 模板和泛型编程)std::move

    1. 标准库定义 / / 在返回类型和类型转换中也要用到 typename, 参见 16.1.3 节( 第 593 页 ) reference 是在 16.2.3 节( 第 605 页 ) 中介绍的 ...

  4. std::move C++11 标准新特性: 右值引用与转移语义

    新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...

  5. 详解C++移动语义std::move()

    目录 1. C++move的概念 2. C++move的特点 3. 左值.右值与左值引用.右值引用 3.1 左值和右值的概念 3.2 左值引用和右值引用 4. std::move详解 4.1 std: ...

  6. Cpp / std::move 原理

    零.功能和源码 std::move 是一个类型转换器,将左值转换成右值,其实现如下: template <typename T> typename remove_reference< ...

  7. C++11 std::shared_ptr的std::move()移动语义底层分析

    std::shared_ptr的std::move()移动语义底层分析 执行std::move()之前: 执行std::move()之后: 结论:一个浅拷贝 sizeof(std::shared_pt ...

  8. [C/C++]关于C++11中的std::move和std::forward

    http://blog.sina.com.cn/s/blog_53b7ddf00101p5t0.html std::move是一个用于提示优化的函数,过去的c++98中,由于无法将作为右值的临时变量从 ...

  9. 【C++ Primer | 16】std::move和std::forward、完美转发

    右值引用应该是C++11引入的一个非常重要的技术,因为它是移动语义(Move semantics)与完美转发(Perfect forwarding)的基石: 移动语义:将内存的所有权从一个对象转移到另 ...

  10. c++11之std::move()

    在c++11中引入了std::move(),目的是将左值转换为右值,一般与右值引用一起使用. 先说下左值与右值的区别: 左值:能被赋值的值,能取到地址的值.例如: int a = 100; 右值:临时 ...

最新文章

  1. 二维数组存放多个字符串_二维数组中输出多个最值及其下标。(仅供参考)
  2. centeros7 mysql,center os 7 Mysql 安装
  3. 本地突破XP系统权限
  4. python 判断是否是int/string/类型的函数
  5. POJ2154(Pólya定理与欧拉函数优化)
  6. php集成paypal接口,PHP中集成PayPal标准支付,php集成paypal标准_PHP教程
  7. Python中fastapi构建的web项目进行docker部署
  8. Codeforces Round #460 (Div. 2)
  9. Revip MEP二次开发之“连接弯头”
  10. python清除历史记录_只需python两行代码,就能获取你的浏览器历史浏览记录
  11. 8、MySQL Workbench导入数据库提示Failed to open required defaults file:xxx.cnf
  12. android 7 蓝牙版本,Android N及高版本蓝牙适配
  13. 不忘初心,成于自渡——记录2020年的自己
  14. 百度搜索结果页面的参数_反馈搜索结果用时(rsv_sug4)
  15. 原创 关于微信拼车小程序开发的需求分析(分析建模)
  16. mount gives unknown filesystem type 'vboxsf' 解决方法
  17. 关于《完全用Linux工作》的思考
  18. HPUX 11iV3 LVM新变化
  19. flask-restful 和 blueprint
  20. 我用过的几款电路设计EDA软件

热门文章

  1. 关于推荐系统中的冷启动问题探讨(Approaching the Cold Start Problem in Recommender Systems)...
  2. CentOS中zip压缩和unzip解压缩命令详解
  3. Android 颜色渲染(六) RadialGradient 环形渲染
  4. JavaScript学习_第2章_JS语法规则
  5. JavaScript的类型转换(字符转数字,数字转字符)
  6. Python操作SQLAlchemy之连表操作
  7. [USACO13JAN] Seating
  8. 复制加网站信息的javascript代码及对应的javascript阻止命令
  9. 搭建高可用 RocketMQ 集群
  10. Python 下载的 11 种姿势