C++ move semantic移动语义介绍

目录
  • 前言
  • 移动构造
  • 为什么我们需要move semantic

前言

在说移动语义之前 本文作者假设你已经具备了深拷贝浅拷贝左值右值等基本概念 本文不会再过多叙述 那么接下来 让我们开始吧

Tips:(警告 警告 警告 警告)在阅读本文章之前 作者首先提醒 线代编译器有RVO和NRVO等一系列优化策略 除非你明确知道你要使用std::move 不然我并不是很推荐你使用移动语义 他很有可能是无意义的

移动构造

在说移动语义之前 让我们先来说说移动构造这玩意

我们都知道 深拷贝是会把在堆区的内存一起拷贝的 那么如果我们明确知道一个对象并不会再继续使用 但是同时我们又想拿到他堆区的资源的时候 我们应该怎么办呢? 移动构造给我们提供了这种能力 代码如下所示:

class MoveClass
{
public:
	int* p;
	MoveClass()
	{
		p = new int();
		std::cout << "默认构造调用" << std::endl;
	}
	~MoveClass()
	{
		std::cout << "析构函数调用" << std::endl;
		if (!p)
			delete p;
	}
	MoveClass(MoveClass& tmp)
	{

	}
	 MoveClass(MoveClass&& tmp)
	{
		std::cout << "移动构造函数调用" << std::endl;
		this->p = tmp.p;
		tmp.p = nullptr;
	}
	MoveClass& operator=(MoveClass&& tmp)
	 {
		 std::cout << "移动构造函数调用" << std::endl;
		 this->p = tmp.p;
		 tmp.p = nullptr;
	 }
};
MoveClass MoveClassTest(MoveClass d)
{
	return MoveClass();
}
int main()
{
	MoveClass cc;
	//好 接下来我们不再想使用c了 但是堆区的资源我们并不想拷贝 那么使用如下构造方式
	MoveClass d(std::move(cc));
	system("pause");
}

移动前数据如下图所示:

移动后数据如下图所示:

程序输出结果:

为什么我们需要move semantic

设想一个场景 我们在一个作用域申请了一个超级大的string 如下图所示

#include <iostream>
#include <string.h>
void test1(std::string s)
{
	std::cout << "test1:" << s.c_str()<<std::endl;;
}
void test()
{
	std::string s = "超级大的string";
	test1(s);
	std::cout <<"test:"<< s.c_str() << std::endl;
	return;
}
int main()
{
	test();
	system("pause");
}

运行结果如下:

你们就要说了 有啥用啊 但是只要你懂一点c++ 你就会知道 在test中的s我们是不需要了的 也就是我们在test是不想再继续使用s的 但是在我们调用test1的时候 我们又重新拷贝了s一份 那么性能是不是就浪费了呢?如果这个string超级大 你的程序是不是就很垃呢

我们只需要简简单单的加一个std::move 他就不是拷贝 而只是单纯的移动指针 如下

#include <iostream>
#include <string.h>
void test1(std::string s)
{
	std::cout << "test1:" << s.c_str()<<std::endl;;
}
void test()
{
	std::string s = "超级大的string";
	test1(std::move(s));
	std::cout <<"test:"<< s.c_str() << std::endl;
	return;
}
int main()
{
	test();
	system("pause");
}

运行结果如下:

这就是他最最最本质的作用 一个东西是左值时 你仍然想要他去触发移动构造记住 其他时候你并不需要去考虑 因为编译器有优化懂吗 不要尝试自己去干扰编译器的优化 除非你真的非常非常非常清楚你自己正在干什么

到此这篇关于C++ move semantic移动语义介绍的文章就介绍到这了,更多相关C++ move semantic内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入了解c++11 移动语义与右值引用

    1.移动语义 C++11新标准中一个最主要的特性就是提供了移动而非拷贝对象的能力.如此做的好处就是,在某些情况下,对象拷贝后就立即被销毁了,此时如果移动而非拷贝对象会大幅提升性能.参考如下程序: //moveobj.cpp #include <iostream> #include <vector> using namespace std; class Obj { public: Obj(){cout <<"create obj" << e

  • 详解C++11中的右值引用与移动语义

    C++11的一个最主要的特性就是可以移动而非拷贝对象的能力.很多情况都会发生对象的拷贝,有时对象拷贝后就立即销毁,在这些情况下,移动而非拷贝对象会大幅度提升性能. 右值与右值引用 为了支持移动操作,新标准引入了一种新的引用类型--右值引用,就是必须绑定到右值的引用.我们通过&&而不是&来获得右值引用.右值引用一个重要的特性就是只能绑定到将要销毁的对象. 左值和右值是表达式的属性,一些表达式生成或要求左值,而另一些则生成或要求右值.一般而言,一个左值表达式表示的是一个对象的身份,而右

  • C++学习之移动语义与智能指针详解

    移动语义 1.几个基本概念的理解 (1)可以取地址的是左值,不能取地址的就是右值,右值可能存在寄存器,也可能存在于栈上(短暂存在栈)上 (2)右值包括:临时对象.匿名对象.字面值常量 (3)const 左值引用可以绑定到左值与右值上面,称为万能引用.正因如此,也就无法区分传进来的参数是左值还是右值. const int &ref = a;//const左值引用可以绑定到左值 const int &ref1 = 10;//const左值引用可以绑定到右值 (4)右值引用:只能绑定到右值不能绑

  • C++模板编程特性之移动语义

    目录 C++的值类型 右值引用与移动构造和移动赋值 C++的值类型 我们知道,每个变量都有类型,或整形或字符型等来进行了分类,不仅如此,C++表达式(带有操作数的操作符.字面量.变量名等)在类型的属性上,还有一种属性,即值类别(value category).且每个表达式只属于三种基本值尖别中的一种:左值(lvalue),右值(rvalue),将亡值(xvalue),每个值类别都与某种引用类型对应. 其中,左值和将亡值成为泛左值(generalized value,gvalue),纯右值和将亡值

  • C++左值与右值,右值引用,移动语义与完美转发详解

    目录 C++——左值与右值.右值引用.移动语义与完美转发 一.左值和右值的定义 二.如何判断一个表达式是左值还是右值(大多数场景) 三.C++右值引用 四.std::move()与移动语义 五. 完美转发 总结 C++——左值与右值.右值引用.移动语义与完美转发 在C++或者C语言中,一个表达式(可以是字面量.变量.对象.函数的返回值等)根据其使用场景不同,分为左值表达式和右值表达式. 一.左值和右值的定义 1.左值的英文为locator value,简写为lvalue,可意为存储在内存中.有明

  • C++ move semantic移动语义介绍

    目录 前言 移动构造 为什么我们需要move semantic 前言 在说移动语义之前 本文作者假设你已经具备了深拷贝浅拷贝左值右值等基本概念 本文不会再过多叙述 那么接下来 让我们开始吧 Tips:(警告 警告 警告 警告)在阅读本文章之前 作者首先提醒 线代编译器有RVO和NRVO等一系列优化策略 除非你明确知道你要使用std::move 不然我并不是很推荐你使用移动语义 他很有可能是无意义的 移动构造 在说移动语义之前 让我们先来说说移动构造这玩意 我们都知道 深拷贝是会把在堆区的内存一起

  • C++移动语义介绍与使用讲解

    目录 引入移动语义 std::move 引入移动语义 为了能够理解移动语义的目的,我们先从整成的一个类进行示范,示例如下: class TestClass { public: TestClass(int s) :m_number(s) { cout << "constructor!\n"; } ~TestClass() { cout << "destructor!\n"; } // 拷贝构造 TestClass(const TestClass

  • 一文搞懂c++中的std::move函数

    目录 前言 左值和右值 左值引用 右值引用 std::move函数 remove_reference源码剖析 std::forward源码剖析 std::move()源码剖析 小结 std::move使用场景 实例:vector::push_back使用std::move提高性能 万能引用 引用折叠 完美转发 前言 在探讨c++11中的Move函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表

  • Java内存模型final的内存语义

    目录 1.final域的重排序规则final 2.写final域的重排序规则 3.读final与的重排序规则 4.final域为引用类型 5.为什么final引用不能从构造函数内"逸出" 6.final语义在处理器中的实现 7.JSR-133为什么要增强final的语义 上篇并发编程之Java内存模型volatile的内存语义介绍了volatile的内存语义,本文讲述的是final的内存语义,相比之下,final域的读和写更像是普通变量的访问. 1.final域的重排序规则final

  • win10 mysql导出csv的两种方式

    win10导出csv有两种方式,第一种是借助工具,Navicat for Mysql是一个非常好用的mysql可视化工具,可以导出多种格式的数据,但是也有其局限.第二种是原始SQL语句导出. Navicat For Mysql 安装软件,这里有绿色免费版,非常好用,链接:https://pan.baidu.com/s/1HZNzq_16M5yrq9hAMfNOmA 提取码:848h .打开软件,建立数据库连接,然后选择对应的表,右键->导出向导,选择格式即可. SQL导出 这里面有几个地方会出错

  • C++11 并发指南之Lock 详解

    在 < C++11 并发指南三(std::mutex 详解)>一文中我们主要介绍了 C++11 标准中的互斥量(Mutex),并简单介绍了一下两种锁类型.本节将详细介绍一下 C++11 标准的锁类型. C++11 标准为我们提供了两种基本的锁类型,分别如下: std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁. std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制. 另外还提供了几个与锁类型相关的

  • C++11中value category(值类别)及move semantics(移动语义)的介绍

    前言 C++11之前value categories只有两类,lvalue和rvalue,在C++11之后出现了新的value categories,即prvalue, glvalue, xvalue.不理解value categories可能会让我们遇到一些坑时不知怎么去修改,所以理解value categories对于写C++的人来说是比较重要的.而理解value categories离不开一个概念--move semantics.了解C++11的人我相信都了解了std::move,右值引用

  • C++移动语义详细介绍使用

    目录 1.移动构造函数 2.右值引用 3.std::move()将左值强制转换为右值引用 4.拷贝语义和移动语义 1.移动构造函数 移动语义就是使用移动构造函数来构造对象. 我们知道在类中如果存在指针数据成员,那么我们就一定要写拷贝构造函数,进行深拷贝 如下所示,就是拷贝构造函数的用法: #include<iostream> using namespace std; class A { public: int * ptr; A():ptr(new int(0)) { cout<<&

  • 浅析C++11中的右值引用、转移语义和完美转发

    1. 左值与右值: C++对于左值和右值没有标准定义,但是有一个被广泛认同的说法:可以取地址的,有名字的,非临时的就是左值;不能取地址的,没有名字的,临时的就是右值. 可见立即数,函数返回的值等都是右值;而非匿名对象(包括变量),函数返回的引用,const对象等都是左值. 从本质上理解,创建和销毁由编译器幕后控制的,程序员只能确保在本行代码有效的,就是右值(包括立即数);而用户创建的,通过作用域规则可知其生存期的,就是左值(包括函数返回的局部变量的引用以及const对象),例如: int& fo

随机推荐