原文出自https://www.cnblogs.com/ldlchina/p/6608154.html

感谢原创作者,以下为原文。


右值引用(及其支持的Move语意和完美转发)是C++0x加入的最重大语言特性之一。从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题。从语言本身讲,它健全了C++中的引用类型在左值右值方面的缺陷。从库设计者的角度讲,它给库设计者又带来了一把利器。从库使用者的角度讲,不动一兵一卒便可以获得“免费的”效率提升…

下面用实例来深入探讨右值引用。

1.什么是左值,什么是右值,简单说左值可以赋值,右值不可以赋值。以下面代码为例,“ A a = getA();”该语句中a是左值,getA()的返回值是右值。

#include "stdafx.h"
#include <iostream>class A
{
public:A() { std::cout << "Constructor" << std::endl; }A(const A&) { std::cout << "Copy Constructor" << std::endl; }~A() {}
};static A getA()
{A a;return a;
}int main()
{A a = getA();return 0;
}

运行以上代码,输出结果如下:

Constructor
Copy Constructor

可以看到A的构造函数调用一次,拷贝构造函数调用了一次,构造函数和拷贝构造函数是消耗比较大的,这里是否可以避免拷贝构造?C++11做到了这一点。

2.添加A的移动构造函数,代码如下:

#include "stdafx.h"
#include <iostream>class A
{
public:A() { std::cout << "Constructor" << std::endl; }A(const A&) { std::cout << "Copy Constructor" << std::endl; }A(const A&&) { std::cout << "Move Constructor" << std::endl; }~A() {}
};static A getA()
{A a;return a;
}int main()
{A a = getA();return 0;
}

运行以上代码,输出结果:

Constructor
Move Constructor

这样就没有调用拷贝构造函数,而是调用移动构造。这里并没有看到移动构造的优点。

3.修改代码,给A类添加一个成员变量如下:

#include "stdafx.h"
#include <iostream>
#include <vector>class B
{
public:B() {}B(const B&) { std::cout << "B Constructor" << std::endl; }
};class A
{
public:A(): m_b(new B()) { std::cout << "A Constructor" << std::endl; }A(const A& src) :m_b(new B(*(src.m_b))){ std::cout << "A Copy Constructor" << std::endl;}A(A&& src) :m_b(src.m_b){src.m_b = nullptr;std::cout << "A Move Constructor" << std::endl;}~A() { delete m_b; }private:B* m_b;
};static A getA()
{A a;std::cout << "================================================" << std::endl;return a;
}int main()
{A a = getA();std::cout << "================================================" << std::endl;A a1(a);return 0;
}

运行以上代码,输出结果:

A Constructor
================================================
A Move Constructor
================================================
B Constructor
A Copy Constructor

“ A a = getA();”调用的是A的移动构造,“ A a1(a); ”调用的是A的拷贝构造。A的拷贝构造需要对成员变量B进行深拷贝,而A的移动构造不需要,很明显,A的移动构造效率高。

4.std::move语句可以将左值变为右值而避免拷贝构造,修改代码如下:

#include "stdafx.h"
#include <iostream>
#include <vector>class B
{
public:B() {}B(const B&) { std::cout << "B Constructor" << std::endl; }
};class A
{
public:A(): m_b(new B()) { std::cout << "A Constructor" << std::endl; }A(const A& src) :m_b(new B(*(src.m_b))){ std::cout << "A Copy Constructor" << std::endl;}A(A&& src) noexcept :m_b(src.m_b){src.m_b = nullptr;std::cout << "A Move Constructor" << std::endl;}~A() { delete m_b; }private:B* m_b;
};static A getA()
{A a;std::cout << "================================================" << std::endl;return a;
}int main()
{A a = getA();std::cout << "================================================" << std::endl;A a1(a);std::cout << "================================================" << std::endl;A a2(std::move(a1));return 0;
}

运行以上代码,输出结果:

A Constructor
================================================
A Move Constructor
================================================
B Constructor
A Copy Constructor
================================================
A Move Constructor

“ A a2(std::move(a1));”将a1转换为右值,因此a2调用的移动构造而不是拷贝构造。

5.赋值操作符也可以是移动赋值。

#include "stdafx.h"
#include <iostream>
#include <vector>class B
{
public:B() {}B(const B&) { std::cout << "B Constructor" << std::endl; }
};class A
{
public:A(): m_b(new B()) { std::cout << "A Constructor" << std::endl; }A(const A& src) :m_b(new B(*(src.m_b))){ std::cout << "A Copy Constructor" << std::endl;}A(A&& src) :m_b(src.m_b){src.m_b = nullptr;std::cout << "A Move Constructor" << std::endl;}A& operator=(const A& src) noexcept{if (this == &src)return *this;delete m_b;m_b = new B(*(src.m_b));std::cout << "operator=(const A& src)" << std::endl;return *this;}A& operator=(A&& src) noexcept{if (this == &src)return *this;delete m_b;m_b = src.m_b;src.m_b = nullptr;std::cout << "operator=(const A&& src)" << std::endl;return *this;}~A() { delete m_b; }private:B* m_b;
};static A getA()
{A a;std::cout << "================================================" << std::endl;return a;
}int main()
{A a = getA();//移动构造std::cout << "================================================" << std::endl;A a1(a);//拷贝构造std::cout << "================================================" << std::endl;A a2(std::move(a1));//移动构造std::cout << "================================================" << std::endl;a2 = getA();//移动赋值std::cout << "================================================" << std::endl;a2 = a1;//拷贝赋值return 0;
}

Howard备注:请注意上面的 A a = getA()和 a2 = getA() 赋值是不一样的!

运行以上代码,输出结果:

A Constructor
================================================
A Move Constructor
================================================
B Constructor
A Copy Constructor
================================================
A Move Constructor
================================================
A Constructor
================================================
A Move Constructor
operator=(const A&& src)
================================================
B Constructor
operator=(const A& src)

总之尽量给类添加移动构造和移动赋值函数,而减少拷贝构造和拷贝赋值的消耗。 移动构造,移动赋值要加上noexcept,用于通知标准库不抛出异常。

参考链接:

http://en.cppreference.com/w/cpp/language/move_constructor

【C++】探讨std::move()作用,查到的《C++11右值引用和std::move语句实例解析》相关推荐

  1. move std 函数 示例_C++11右值引用和std::move语句实例解析(推荐)

    右值引用(及其支持的Move语意和完美转发)是C++0x将要加入的最重大语言特性之一.从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题.从语言本身讲,它健全了C++中的引用类型 ...

  2. C++11右值引用和std::move语句实例解析

    关键字:C++11,右值引用,rvalue,std::move,VS 2015 OS:Windows 10 右值引用(及其支持的Move语意和完美转发)是C++0x加入的最重大语言特性之一.从实践角度 ...

  3. c++ 杂谈 右值引用与 std::move()

    c++ 杂谈 右值引用与 std::move() 如果不清楚概念,可以看一下这篇文章 前言:左值与右值 说到左值与右值的起源,我们甚至可以追溯到 c 语言.我们先看下面一段代码: int main ( ...

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

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

  5. 《Effective Modern C++》学习笔记之条款二十五:针对右值引用实施std::move,针对万能引用实施std::forward

    我们知道,一个函数接受一个右值引用参数后将变成左值(可以对其取地址),所以如果在函数内部想要继续使用其右值属性,就可以对其实施std::move,将形参左值转换为右值. 而对于万能引用,因为其实参可能 ...

  6. C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

    这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...

  7. std::move 左值右值 左值引用右值引用

    参考:https://blog.csdn.net/daaikuaichuan/article/details/88371948 https://zhuanlan.zhihu.com/p/9458820 ...

  8. C++11中的右值引用及move语义编程

    C++0x中加入了右值引用,和move函数.右值引用出现之前我们只能用const引用来关联临时对象(右值)(造孽的VS可以用非const引用关联临时对象,请忽略VS),所以我们不能修临时对象的内容,右 ...

  9. C++ 右值引用 | 左值、右值、move、移动语义、引用限定符

    文章目录 C++11为什么引入右值? 区分左值引用.右值引用 move 移动语义 移动构造函数 移动赋值运算符 合成的移动操作 小结 引用限定符 规定this是左值or右值 引用限定符与重载 C++1 ...

最新文章

  1. 关于python导入模块和package的一些深度思考
  2. Jenkins Pipeline构建流水线发布
  3. 6.3 Spring Boot集成mongodb开发
  4. 《圣洁》的读后感作文3000字
  5. 让创新触手可及,阿里云容器服务 ACK 发行版开放免费下载
  6. conda常用命令汇总
  7. dijkstra算法学习
  8. Java实验方法参数传递与递归_4.3类的结构之二:方法(return,重载,可变个数形参,值传递,递归)...
  9. 一套代码在不同的电脑执行快慢_电脑如何选配之硬盘篇
  10. 如何监控 Tomcat?Zabbix 与 Cloud Insight 对比
  11. 06_day初始化PIC
  12. 【Modelsim】下载安装教程
  13. php制作特效文字,PPT制作文字特效 PPT特效文字制作教程
  14. k8s [kubelet-check] Initial timeout of 40s passed.解决方案
  15. 2015-2016 Petrozavodsk Winter Training Camp, Moscow SU Trinity Contest
  16. 微软与GitHub百人签名,力挺996.ICU项目
  17. nuvoton uboo2013引导流程 2 - spl
  18. Java读写Excel之HSSFWorkbook、XSSFWorkbook、Workbook
  19. python--元组tuple
  20. Ambari2.7.3自定义安装Ambari-Doris-Service

热门文章

  1. CSS插入背景图片并且充满整个容器
  2. iOS项目开发实战——设置视图的透明度改变动画
  3. 我是一只IT小小鸟 感受
  4. python中字符串的布尔值_day02python中的基本数据类型-布尔值和字符串
  5. 京东跟便利店搞一起了谁爽?谁不爽?
  6. ink 没有找到 或上一个增量链接没有生成它;正在执行完全链接
  7. 使用WebUploader解决安卓微信浏览器上传图片中遇到的bug
  8. 脑梗偏瘫怎么康复?顾连康复医院治疗脑梗偏瘫效果
  9. 聊聊Mybatis的缓存
  10. java毕业设计基于Bootstrap的读书网站设计与实现(附源码、数据库)