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右值引用和移动语义的探究
随机推荐
- HTML__post 和 get区别【URL】
一.get和post的区别: 表单提交中get和post方式的区别有5点 1.get是从服务器上获取数据,post是向服务器传送数据. 2.get是把参数数据队列加到提交表单的ACTION属性所指的U ...
- JAVA中的访问修饰符和包
一.JAVA访问修饰符 访问修饰符,用来控制类中成员的可见性 有四个访问修饰符,分别是:default,private,public,protected 1.default(默认):默认权限,不用写的 ...
- Linux驱动技术(五) _设备阻塞/非阻塞读写
等待队列是内核中实现进程调度的一个十分重要的数据结构,其任务是维护一个链表,链表中每一个节点都是一个PCB(进程控制块),内核会将PCB挂在等待队列中的所有进程都调度为睡眠状态,直到某个唤醒的条件发生 ...
- CoreData和FMDB你用哪个?
概括: 我们先说说这两个东西,CoreData 和 FMDB,其实就我自己而言觉得这两个都不错,刚开始是接触FMDB的,CoreData是工作后自己看的.苹果推荐开发者去使用CoreData,但 FM ...
- 5个Android开发中比较常见的内存泄漏问题及解决办法
android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了. 内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...
- ArcObjects与ArcEngine的联系与区别
ArcObjects与ArcEngine的联系与区别 AO一般指的是桌面产品开发组件,需要在桌面环境中才能够使用,最典型的就是嵌入式VBA开发.但是这样带来的弊端和OFFICE等相关软件一样明显,就是 ...
- Python简单爬虫记录
为了避免自己忘了Python的爬虫相关知识和流程,下面简单的记录一下爬虫的基本要求和编程问题!! 简单了解了一下,爬虫的方法很多,我简单的使用了已经做好的库requests来获取网页信息和Beauti ...
- 使用Python以优雅的方式实现根据shp数据对栅格影像进行切割
目录 前言 涉及到的技术 优雅切割 总结 一.前言 前面一篇文章(使用Python实现子区域数据分类统计)讲述了通过geopandas库实现对子区域数据的分类统计,说白了也就是如何根据一 ...
- 读书笔记 effctive c++ Item 20 优先使用按const-引用传递(by-reference-to-const)而不是按值传递(by value)
1. 按值传递参数会有效率问题 默认情况下,C++向函数传入或者从函数传出对象都是按值传递(pass by value)(从C继承过来的典型特性).除非你指定其他方式,函数参数会用实际参数值的拷贝进行 ...
- Loadrunner之脚本编写
先打开loadrunner的服务器(打开成功之后会出现一个绿色的X) 以订票系统为例(http://127.0.0.1:1080/WebTours/) 录制一个登陆的脚本. 利用C语言编写一个简单的脚 ...