关键字: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语句实例解析的更多相关文章

  1. C++ 11 右值引用以及std::move

    转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...

  2. C++ 11中的右值引用以及std::move

    看了很多篇文章,现在终于搞懂了C++ 中的右值以及std::move   左值和右值最重要的区别就是右值其实是一个临时的变量 在C++ 11中,也为右值引用增加了新语法,即&&   比 ...

  3. Item 25: 对右值引用使用std::move,对universal引用则使用std::forward

    本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 右值引用只能绑定那些有资格被move的对象上去.如 ...

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

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

  5. 右值引用和std::move函数(c++11)

    1.对象移动 1)C++11新标准中的一个最主要的特性就是移动而非拷贝对象的能力 2)优势: 在某些情况下,从旧内存拷贝到新内存是不必要的,此时对对象进行移动而非拷贝可以提升性能 有些类如IO类或un ...

  6. 透彻理解C++11新特性:右值引用、std::move、std::forward

    目录 浅拷贝.深拷贝 左值.右值 右值引用类型 强转右值 std::move 重新审视右值引用 右值引用类型和右值的关系 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forw ...

  7. C++11右值引用

    [C++11右值引用] 1.什么是左值?什么是右值? 左值是表达式结束后依然存在的对象:右值是表达式结束时就不再存在的对象. 2.std::move的作用是什么? std::move用于把任意类型转化 ...

  8. c++11 右值引用和移动语义

    什么是左值.右值 最常见的误解: 等号左边的就是左值,等号右边的就是右值 左值和右值都是针对表达式而言的, 左值是指表达式结束后依然存在的持久对象 右值是指表达式结束时就不再存在的临时对象区分: 能对 ...

  9. 关于C++11右值引用和移动语义的探究

    关于C++11右值引用和移动语义的探究

随机推荐

  1. java中函数是值传递还是引用传递?

    相信有些同学跟我一样,曾经对这个问题很疑惑.在网上也看了一些别人说的观点,评论不一.有说有值传递和引用传递两种,也有说只有值传递的,这里只说下个人见解 先看一个例子 public class Test ...

  2. 自己开发轻量级ORM(三)

    上一篇中简单分享了下ORM的设计思路.现在开始讲如何用代码来实现上篇的设计模型. 我们建2个类库来分别抽象数据库表结构关系映射和SQL增删改查操作. 打开VS2010,新建2个类库.分别起名为Mode ...

  3. CSS_position

    1. HTML Code: <div id="example"> <div id="div-before"> <p>id = ...

  4. 报表学习总结(一)——ASP.NET 水晶报表(Crystal Reports)的简单使用

    一.水晶报表简介 Crystal Reports(水晶报表)是一款商务智能(BI)软件,主要用于设计及产生报表.水晶报表是业内最专业.功能最强的报表系统,它除了强大的报表功能外.最大的优势是实现了与绝 ...

  5. 腾讯优图及知脸(ZKface)人脸比对接口测试(python)

    一.腾讯优图 1.开发者地址:http://open.youtu.qq.com/welcome/developer 2.接入流程:按照开发者页面的接入流程接入之后,创建应用即可获得所需的AppID.S ...

  6. App开发外包必须注意的四大骗局

    在app外包过程中有很多需要注意的事项,今天专门挑选注意事项中的"骗局"这个话题来与大家分享一些的常见骗局及其细节. 无论是从新闻还是身边的朋友,我们都经常可以听见"xx ...

  7. centos 7安装es 及异常处理

    首先,我们从官网下载zip包:(官网:https://www.elastic.co/downloads/elasticsearch)   直接使用浏览器下载可能会很慢,我一般会copy下载链接,然后w ...

  8. CentOS 6.4 安装setuptools 和 pip

    若有报错信息:setuptools Compression requires the (missing) zlib module,需执行步骤1-2(否则可忽略) 1. 安装zlib 和 zlib-de ...

  9. docker - 容器里安装mysql

    在docker中安装mysql ubuntu官方镜像是精简的ubuntu系统,很多软件和库没有安装,所以直接安装mysql的话依赖较多,建议直接从源码编译安装mysql 通过命令行安装 先启动一个容器 ...

  10. shiyandaima

    //jidaxiangronglei #include<iostream> #include<iostream> #include<iomanip> #includ ...