C++11右值引用和std::move语句实例解析
关键字:C++11,右值引用,rvalue,std::move,VS 2015
OS:Windows 10
右值引用(及其支持的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 ;
}
运行以上代码,输出结果如下:
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 ;
}
运行以上代码,输出结果:
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 ;
}
运行以上代码,输出结果:
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 ;
}
运行以上代码,输出结果:
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 ;
}
运行以上代码,输出结果:
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++11右值引用和std::move语句实例解析的更多相关文章
- C++ 11 右值引用以及std::move
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...
- C++ 11中的右值引用以及std::move
看了很多篇文章,现在终于搞懂了C++ 中的右值以及std::move 左值和右值最重要的区别就是右值其实是一个临时的变量 在C++ 11中,也为右值引用增加了新语法,即&& 比 ...
- Item 25: 对右值引用使用std::move,对universal引用则使用std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 右值引用只能绑定那些有资格被move的对象上去.如 ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
- 右值引用和std::move函数(c++11)
1.对象移动 1)C++11新标准中的一个最主要的特性就是移动而非拷贝对象的能力 2)优势: 在某些情况下,从旧内存拷贝到新内存是不必要的,此时对对象进行移动而非拷贝可以提升性能 有些类如IO类或un ...
- 透彻理解C++11新特性:右值引用、std::move、std::forward
目录 浅拷贝.深拷贝 左值.右值 右值引用类型 强转右值 std::move 重新审视右值引用 右值引用类型和右值的关系 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forw ...
- C++11右值引用
[C++11右值引用] 1.什么是左值?什么是右值? 左值是表达式结束后依然存在的对象:右值是表达式结束时就不再存在的对象. 2.std::move的作用是什么? std::move用于把任意类型转化 ...
- c++11 右值引用和移动语义
什么是左值.右值 最常见的误解: 等号左边的就是左值,等号右边的就是右值 左值和右值都是针对表达式而言的, 左值是指表达式结束后依然存在的持久对象 右值是指表达式结束时就不再存在的临时对象区分: 能对 ...
- 关于C++11右值引用和移动语义的探究
关于C++11右值引用和移动语义的探究
随机推荐
- 如何用webbrowser获取ajax动态生成的网页的源码?
1.步骤一:修改IE内核的版本(这个方法厉害了) public Form1() { InitializeComponent();int BrowserVer, RegVal; // get the i ...
- intelliJ IDEA创建web工程
1.创建project,也就是eclipse里的workspace,eclipse里1个工作空间里可以创建多个工程,idea的一个工作空间里只创建1个工程. File -- New -- Projec ...
- 【前端】:css
前言: 关于前端的第二篇博客,会写关于css的,内容比较基础.写完这篇博客,会做一个类似美乐乐家具的界面.good luck to me~ 一.css-引用样式 标签上设置style属性: <b ...
- ssh无法远程登陆别的机器
ssh无法远程登陆别的机器,提示报错: ssh: symbol lookup error: ssh: undefined symbol: EVP_aes_128_ctr 解决方法如下: 给相应配置文件 ...
- 10步完成Abp(.net core)+Vue的Demo?
1.去abp官网生成项目,选择.net core1.x版本 2.Nuget还原包,需装dotnet core1.1等. 3.新增一个entity,并加入到上下文中 4.然后cmd命令行工具切换到项目 ...
- matlab for循环的三种类型
学习了一半了,发现一个好网站,就是我想写这篇博客用的,网络真是个好东西!纪念下国庆啦 网址:http://www.yiibai.com/matlab/matlab_for_loop.html ---- ...
- [java多线程] - Thread&Runnable运用
负载是一个很大的话题,也是一个非常重要的话题.不管是在大的互联网软件中,还是在一般的小型软件,都对负载有一定的要求,负载过高会导致服务器压力过大:负载过低又比较浪费服务器资源,而且当高请求的时候还可能 ...
- 如何居中div?如何居中一个浮动元素?
如何居中div? 给div设置一个宽度,然后添加margin:0 auto属性 div{ width:200px; margin:0 auto; } 如何居中一个浮动元素? <!DOCTYPE ...
- jQuery_第一章_JavaScript基础
JavaScript基础 JavaScript不难,但是对于初学者来讲比较的怪异. 是一种客户端语言,在浏览器执行的.是一种脚本语言,直接就能解释执行的叫脚本代码.像dos命令还有SQL也是. 为什么 ...
- 《剑指offer》— JavaScript(1)二维数组中的查找
二维数组中的查找 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ** ...