C++移动构造与std::move()
背景及问题
如下程序所示:
#include<iostream>
class MyString {
public:
MyString() = default;
MyString(const char* data)
{
printf("%s", "MyString Constructed!!\n");
size = strlen(data);
m_data = new char[size];
memcpy(m_data, data, size);
}
~MyString()
{
if (m_data)
{
printf("%s", "MyString Destroyed!!\n");
delete m_data;
}
}
//copy constructor
MyString(const MyString& other) noexcept
{
printf("%s", "MyString Copyed!!\n");
size = other.size;
m_data = new char[size];
memcpy(m_data, other.m_data, size);
}
private:
char* m_data;
int size;
};
class Entity
{
public:
//constructor
Entity(const MyString& string):m_string(string) {}
private:
MyString m_string;
};
int main()
{
Entity entity("Hello");
return 0;
}
程序说明
程序定义了一个MyString类,其中构造函数和拷贝构造函数需要对传进来的字符串开辟空间并复制内容,另外一个Entity类含有一个MyString成员,并在初始化时复制传入的MyString对象。主程序Main中以常量字符串构造一个entity示例。

运行程序会发现,MyString构造了一次,拷贝一次,程序结束析构两次,符合运行逻辑。“Hello”字符串先通过构造函数构造一个临时变量MyString,临时变量再通过Entity内的构造函数拷贝构造给成员变量m_string
问题在于临时变量拷贝构造需要重新开辟空间,并且“用完即扔”,为什么不直接将“hello”构造好的MyString直接“移动”到Entity?这样会节省空间,提高效率。用此引出移动构造和std::move()
移动构造与std::move()
若要实现将临时变量移动到Entity,首先MyString要加入移动构造,如下:
MyString(MyString&& other) noexcept
{
printf("%s", "MyString Moved!!\n");
size = other.size;
m_data = other.m_data;
//clear origin data
other.size = 0;
other.m_data = nullptr;
}
此为移动构造,接受的是一个右值,构造是直接复制原MyString的size与data,不重新开辟空间做深拷贝。并将原MyString清零。接着对Entity构造时使用std::move通知移动构造函数,如下:
Entity(MyString&& string) :m_string(std::move(string)) {}

需要注意的是
1. Entity右值构造时也可不使用std::move,直接将参数强转为右值类型也可以,std::move相当于通知构造函数以移动构造的方式进行
Entity(MyString&& string) :m_string((MyString&&)string) {}
2. 对于形参为Const YourType &类型的既可以接受左值,也可以接受右值。但是使用std::move会编译错误,因为Const值不能被移动,所以Entity构造仍要单独写一个右值构造
3. MyString移动构造时,复制了临时数据的值还要对其清空,因为数据已经被移动,指针没有置空,析构两次会引起Crash问题
C++移动构造与std::move()的更多相关文章
- 移动构造和移动赋值与std::move
------------------------------------移动构造------------------------------------------ 传统的深拷贝深赋值 对于类中,含有 ...
- C++ 11 右值引用以及std::move
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...
- C++11右值引用和std::move语句实例解析
关键字:C++11,右值引用,rvalue,std::move,VS 2015 OS:Windows 10 右值引用(及其支持的Move语意和完美转发)是C++0x将要加入的最重大语言特性之一.从实践 ...
- c++ 11 移动语义、std::move 左值、右值、将亡值、纯右值、右值引用
为什么要用移动语义 先看看下面的代码 // rvalue_reference.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #includ ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
- item 23: 理解std::move和std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 根据std::move和std::forward不 ...
- Item 25: 对右值引用使用std::move,对universal引用则使用std::forward
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 右值引用只能绑定那些有资格被move的对象上去.如 ...
- [转载]如何在C++03中模拟C++11的右值引用std::move特性
本文摘自: http://adamcavendish.is-programmer.com/posts/38190.htm 引言 众所周知,C++11 的新特性中有一个非常重要的特性,那就是 rvalu ...
- std::move的原理与实现,右值引用的深入理解
这次我真的懂了.... 首先C++11引入了右值引用 && ‘&&’这个要连起来看,是一个整体,C++多了一个关键字而已. 不是引用的引用.是船新的一种语法.那有什么用 ...
- 透彻理解C++11新特性:右值引用、std::move、std::forward
目录 浅拷贝.深拷贝 左值.右值 右值引用类型 强转右值 std::move 重新审视右值引用 右值引用类型和右值的关系 函数参数传递 函数返还值传递 万能引用 引用折叠 完美转发 std::forw ...
随机推荐
- Error parsing HTTP request header--400 bad request
问题描述: JSP中通过form post方式请求URL传入json格式参数报错: 信息: Error parsing HTTP request header Note: further occur ...
- 前端保存JWT的使用方法
我们可以将JWT保存在cookie中,也可以保存在浏览器的本地存储里,我们保存在浏览器本地存储中 浏览器的本地存储提供了sessionStorage 和 localStorage 两种,从属于wind ...
- 在Winform界面中使用自定义控件,丰富界面的效果处理
我们在<SqlSugar开发框架>中,Winform界面开发部分往往也用到了自定义的用户控件,对应一些特殊的界面或者常用到的一些局部界面内容,我们可以使用自定义的用户控件来提高界面的统一性 ...
- 【LeetCode二叉树#12】合并二叉树(巩固层序遍历)
合并二叉树 力扣题目链接(opens new window) 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果 ...
- Python实现ARP攻击
目录 概述 ARP协议 IP转MAC 结构 ARP扫描 开始欺骗 中间人 其他 ARP老化 防御 windows linux 概述 高中的时候,学校有一个商店,会放开WIFI给偷偷带手机去学校的我们使 ...
- [VueJsDev] 基础知识 - ES6循环使用手册
[VueJsDev] 目录列表 https://www.cnblogs.com/pengchenggang/p/17037320.html ES6循环使用手册 ::: details 目录 目录 ES ...
- linux下命令行打开文件夹窗口
方法一: 使用自带的命令:nautilus . 打开当前文件夹 nautilus . 打开指定路径文件夹 nautilus ddd/ccc/ 方法二:xdg-open xdg-open 命令相当于在 ...
- 使用supervisor后台运行celery
一.先安装supervisor 1.安装命令: $ pip install supervisor 如果在沙盒环境下安装不上的话使用: $ apt-get install supervisor 二.安装 ...
- 什么叫运行时的Java程序?
Java程序的运行包含编写.编译和运行三个主要步骤. 1.在编写阶段: 开发人员在Java开发环境中输入程序代码,形成后缀名为.java的Java源文件. 2.在编译阶段: 使用Java编译器对源文件 ...
- Linux环境下Minio的安装部署与启动教程(完整版)
1.概述 MinIO是一个开源.分布式的对象存储系统,专为云原生环境设计.它提供了一个基于标准的Amazon S3兼容接口,使得开发者可以使用熟悉的API在私有云或边缘环境中部署和管理大规模非结构化数 ...