【仿写实现move函数】

news2024/11/16 6:59:08

仿写实现move函数

一、值的类型

在这里插入图片描述

1.左值

描述:能够取地址的值成为左值

int a = 10;
const int b = 15;
int *pa = &a;
const int *pb = &b;

2.纯右值

描述:赤裸裸的字面值 eg(false , 3 , 12.23等)

int a = 13;
int *p = &a;  //取a的地址
int *ptr = &13; //错误,13是一个字面量,无法取地址 

如字面常量 103, 12.23, nullptr;不可以取地址, 称为为纯右值。

3.将亡值

描述:表达式的运行或计算过程中所产生的临时量或临时对象,称之为将亡值;临时量有可能是字面值,也有可能是一个不具名的对象。

算术表达式(a+b …),逻辑表达式(a || b …),比较表达式(a != b …)取地址表达式(&b)等,产生的计算结果相当于字面量,实际存储在 cpu的寄存器中 ,因为计算结果是字面量,所以为纯右值。

如图 在这里插入图片描述

因为c++是面向对象的,所以 i++ 和 ++i 是不一样的, ++i 相当于 i = i + 1; 所以 不会产生临时变量, 而 i++不同,它相当于 将 i 拷贝一份当做副本,然后将原来的 i 进行加 1 操作,最后将 副本 的值返回。 副本是不具名的,所以是 将亡值,而 返回的值是 字面量 所以 i++ 为纯右值

不具名对象如图

在这里插入图片描述

编译后会报错 test.cpp(17): error C2102: “&”要求左值,。

因为 Int(13) 程序运行过程中所产生了不具名对象,将亡值。 不可以取地址, 所以&Int(13)错误 。

int fun()
{
    int value = 10;
    return value;
}
int main()
{
    int i = 0;
    int a = 1;
    i = a + b;
    i++;
    &b;
    a = fun(); //返回时在主栈帧中构造临时量,是将亡值,纯右值。
    return 0;
}

流程图 图 2.2

在这里插入图片描述

当fun函数return 时 ,其栈帧空间会被回收,此时先在主栈帧中创建一个将亡值对象(xvalue) 将返回的值赋给将亡值,回到主函数栈帧中会再将将亡值对象的值赋给 a.

二、引用

基本原则:

1.声明引用的时候必须初始化,且一旦绑定,不可把引用绑定到其他对象;即引用必须初始化,不能对引用重定义

2.对引用的一切操作,就相当于对原对象的操作

1.引用与函数重载

void fun(int& val)
{
	cout << "LeftRef" << endl;
}
void fun(const int & val)
{
    cout << "Const LeftRef" << endl;
}
void fun(int&& val)
{
	cout << "RightRef" << endl;
}
int main()
{
	int a = 10; 
	const int d = 15;
	int&& f = 12; //右值引用f是具名右值引用,编译器会将已命名的右值引用视为左值
	//int&& g = f;  // error,f为具名右值
	fun(a);  
	fun(d);
	fun(f);
    fun(13);
    return 0;
}

运行结果:

在这里插入图片描述

结论:

​ 1.int& a = 10; 右值引用 a 是具名右值引用。

​ 2.编译器会将已命名的右值引用视为左值,所以不能 int && b = a;

2.函数返回值

int func()
{
    int x = 10;
    cout<<"&x: "<<endl;
    return x;
}

int main()
{
	int a = func();
	//int& b = func(); // error; func返回值为右值.
	const int& c = func(); 
	cout << "&c: " << &c << endl;
	int&& d = func();
	cout << "&d: " << &d << endl;

	return 0;
}

运行结果:

在这里插入图片描述

结论:1.函数返回值为将亡值(右值)

​ 2.常性左值引用为万能引用,可以接受右值

3.自定义类

class Int  
{
	int val;
public:
	Int(int x = 0) :val(x)
	{
		cout << "Create Int: " << this << endl;
	}
	Int(const Int& it) :val(it.val)
	{
		cout << this<<" Copy Create Int: <= " << &it << endl;
	}
	Int(Int&& it) :val(it.val)
	{
		it.val = 0;
		cout << this<<" Move Create Int: <= " << &it << endl;
	}
	Int& operator=(const Int& it)
	{
		if (this == &it) return *this;
		val = it.val;
		cout << this << " = " << &it << endl;
		return *this;
	}
	Int& operator=(Int&& it)
	{
		if (this == &it) return *this;
		val = it.val;
		it.val = 0;
		cout << this << " <= " << &it << endl;
		return *this;
	}
	~Int() { cout << "Destroy Int: " << this << endl; } 
};

Int func(int x)
{
	Int tmp(x);
	return tmp;
}

int main()
{
	Int a = func(1);
	cout << "--------------------" << endl;
	Int x(0);
	cout << "--------------------" << endl;
	x = func(2);
	cout << "--------------------" << endl;
	//Int& b = func(3);
	const Int& c = func(4);
	cout << "--------------------" << endl;
	Int&& d = func(5);
	cout << "--------------------" << endl; 
	Int f(a);
	cout << "--------------------" << endl;
	return 0;
}

运行结果

在这里插入图片描述

结论:

1.通过右值引用,比之前少了一次移动构造和一次析构,原因在于右值引用绑定了右值,让临时右值的生
命周期延长了 <主栈帧里创建的不具名对象(将亡值)>

2.函数返回值构建过程和之前分析的一样( 图 2.2

三、std::move的实现

原理:

本质上是将左值强制转换为右值引用,调用对象的移动构造和移动赋值函数,实现对资源的转移。

优点:

当一个对象内部有较大的堆内存或者动态数组时,进行深拷贝会占用cpu资源,而浅拷贝释放资源时会造成对堆区进行重复释放导致非法访问。使用move()语义可以提高性能

使用范围:

move 对于拥有形如对内存、堆区等资源的成员的对象有效

1.未定义的引用类别 && (函数模板中)

template <class _Ty>
void fun(_Ty&&  x) //未定义的引用类型,它必须被初始化,它是左值还是右值引用,取决于它的初始化
{
    int z = 10;
    _Ty y = z;
}
int main()
{
    int a = 1;
    const int b = 2;
    int& c = a;
    const int& d = b;
    fun(10);  
    fun(a);
    fun(b);
    fun(c);
    fun(d);
    return 0;
}

fun(a),fun©: x 的类型为 int& ,y的类型为 int&;

fun(b),fun(d):x的类型为 const int& ,y的类型为const int&;

fun(10):x的类型为 int&& , y 的类型为 int,不具有引用;

结论:

  1. _Ty && 与左值,普通左值引用结和,_Ty为左值引用

  2. _Ty&& 与左值常引用结合,_Ty为左值常性引用

  3. _Ty&& 与右值结合时,_Ty只保留类型,不具有引用属性

  4. _Ty&& 不会破坏掉 对象的const属性

实现流程:

1.我们需用取出对象的引用属性
template <class _Ty>
struct my_remove_reference
{
    using type = _Ty;
    my_remove_reference()
    {
        cout << "_Ty" << endl;
    }
};
template <class _Ty>
struct my_remove_reference<_Ty &>
{
    using type = _Ty;
    my_remove_reference()
    {
        cout << "_Ty" << endl;
    }
};
template <class _Ty>
struct my_remove_reference<_Ty &&>
{
    using type = _Ty;
    my_remove_reference()
    {
        cout << "_Ty" << endl;
    }
};
2.加入适配器,使其具有普适性
template <class _Ty>
using my_remove_reference_t = typename my_remove_reference<_Ty>::type;
3.转换为右值
template <class _Ty>
my_remove_reference_t<_Ty> && my_move(_Ty &&x)
{
    return static_cast<my_remove_reference_t<_Ty>&&>(x);
}

典型错误:使用c语言中的强制类型转换

template <class _Ty>
my_remove_reference_t<_Ty> && my_move(_Ty &&x)
{ 
   return (my_remove_reference_t<_Ty>&&)x; //error,不能使用c语言中的强制类型转换
}

因为常性对象的资源是不能进行移动修改的,而强制类型转换会破坏这一平衡点,而c++的静态类型转换刚好不会去掉const属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1251951.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AVD黑屏

启动android studio的AVD后&#xff0c;无法开启&#xff0c;一直处于黑屏状态 【解决方案】 1.点击 Android Virtual Device Manager中avd后面的编辑按钮 2.点击Show Advanced Settings按钮 3.找到Boot option中的Cold boot并选中 4.重启AVD

企业文件管理软件推荐:2023年5款国内外软件比较

文件管理是现代企业中一项重要而不可避免的任务&#xff0c;不断增长的数据量和不断变化的管理需求使得选择适合自己企业的文件管理软件尤为重要。那么哪些企业文件管理软件值得我们关注呢&#xff1f;本文将为您介绍几款备受好评的企业文件管理软件&#xff0c;帮助您做出明智…

【DevOps】一张图带你了解 DevOps 生态工具

一张图带你了解 DevOps 生态工具 ✅ 协作&#xff08;Collaborate&#xff09;&#xff1a;JIRA、Confluence 大家肯定不陌生了&#xff0c;我之前也写过利用 Jekyll 搭建个人博客的帖子。✅ 构建&#xff08;Build&#xff09;&#xff1a;常用的 SCM&#xff08;Software Con…

一致性 Hash 算法 Hash 环发生偏移怎么解决

本篇是对文章《一文彻底读懂一致性哈希算法》的重写&#xff0c;图文并茂&#xff0c;篇幅较长&#xff0c;欢迎阅读完提供宝贵的建议&#xff0c;一起提升文章质量。如果感觉不错不要忘记点赞、关注、转发哦。原文链接&#xff1a; 《一文彻底读懂一致性Hash 算法》 通过阅读本…

4、LED闪烁

LED亮灭 使用STC-ISP软件的延时计算器自动生成延迟子函数 #include <REGX52.H> #include <INTRINS.H>//延迟函数 void Delay500ms() //12.000MHz {unsigned char i, j, k;//_nop_()需要导入<INTRINS.H>包_nop_();i 4;j 205;k 187;do{do{while (--k);}…

burp suite 2023.10 Intruder模块详解)

burp suite 2023 Intruder模块详解 Intruder 模块是Burp suite的一个重要功能&#xff0c;用于自动化攻击和对目标应用程序进行大规模的攻击测试。 其主要功能包括&#xff1a; Payloads 设置&#xff1a; 用户可以定义不同类型的 payload&#xff0c;例如字典、数字范围、定…

Python 前后端分离项目Vue部署应用

一、视图创建 from django.http import JsonResponse from django.shortcuts import render# Create your views here. from django.views import Viewclass IndexView(View):def get(self,request):# 前后端分离 &#xff08;前端JS代码渲染数据&#xff09;return JsonRespo…

用Python进行数据分析:探索性数据分析的实践与技巧(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Elasticsearch集群部署 head监控插件 Kibana部署 Nginx反向代理 Logstash部署

一、组件介绍1、Elasticsearch&#xff1a;2 、Logstash3、Kibana4、Kafka&#xff1a;5、Filebeat: 二、 Elasticsearch集群部署服务器创建用户安装ES修改配置文件创建数据和日志目录设置JVM堆大小 #7.0默认为4G修改安装目录及存储目录权限系统优化&#xff08;1&#xff09;增…

DGL的图数据处理管道

DGL在 dgl.data 里实现了很多常用的图数据集。它们遵循了由 dgl.data.DGLDataset 类定义的标准的数据处理管道。 DGL推荐用户将图数据处理为 dgl.data.DGLDataset 的子类。该类为导入、处理和保存图数据提供了简单而干净的解决方案。 DGL中的Dataset类 它是处理、导入以及保存…

BTP-K710自定义纸张大小

进入控制面板 输入 control 打开打印机 点击查看设备和打印机 打开打印机属性 鼠标右击 -> 点击打开打印机属性 如果上面没有你想要的尺寸 点标签库 -> 选中Custom Paper-BPLZ -> 然后修改宽度和高度 -> 点击应用 选择Custom Paper-BPLZ 最后点击确定 这样…

计数问题+约瑟夫问题(map)

目录 一、计数问题 二、约瑟夫问题 一、计数问题 #include<iostream> #include<map> using namespace std; int main() {int n,x;cin>>n>>x;map<int,int>m;for(int i1;i<n;i){if(i>1 && i<10){m[i];}else{int temp i;while (…

Task.Run为什么会存在内存泄漏的风险?

由于值类型是拷贝方式的赋值&#xff0c;捕获的本地变量和类成员是指向各自的值&#xff0c;对本地变量的捕获不会影响到整个类。但如果把类中的值类型改为引用类型&#xff0c;那这两者最终指向的是同一个对象值&#xff0c;这是否意味着使用本地变量还是无法避免内存泄漏&…

1.如何修改seruat对象的行名 2.FeaturePlot如何把所有阳性表达的spot放到图的前面

本有解决标题中的两个问题 1.答案是修改不了&#xff0c;不如重新制作一个seurat对象。 试图使用rownames&#xff08;obj&#xff09;featurenames是不成功的 记录 客户需求遇到一个问题&#xff1a;作者提供的rds文件行名为ensemble id&#xff0c;如何改成gene symbol。 …

解决hbuilder使用android studio模拟器不能热更新

hbuilder使用android studio模拟器编&#xff0c;在编写代码时&#xff0c;不能热更新&#xff0c;总是需要重启虚拟机中的程序&#xff0c;hbuilderx的版本是3.1.22&#xff0c;android studio的版本是4.2.2 同时在hbuilderx中出现如下报错信息&#xff1a; 报错信息&#x…

ASP产品通过网络安全专用产品安全认证

什么是网络安全专用产品安全检测&#xff1f; 网络安全专用产品安全检测是指对网络关键设备和网络安全专用产品进行安全性评估和检测&#xff0c;以确保其符合相关标准和法规的要求&#xff0c;能够有效地抵御网络攻击和威胁。该检测由具备资格的机构进行&#xff0c;采用认证…

禁止指定电脑程序运行的2种方法

你可能要问了&#xff0c;为什么要禁止电脑程序运行呢&#xff0c;因为有的公司要净化公司的工作环境&#xff0c;防止某些刺头员工在公司电脑上瞎搞。也有部分家长&#xff0c;是为了防止自己家的孩子利用电脑乱下载东西。 今天就分享2种禁止指定电脑程序运行的方法&#xff1…

C语言SO EASY(ZZULIOJ1220: SO EASY)

题目描述 Superbin最近在研究初等数论&#xff0c;初等数论 是研究数的规律&#xff0c;特别是整数性质的数学分支。它是数论的一个最古老的分支。它以算术方法为主要研究方法&#xff0c;主要内容有整数的整除理论、同余理论、连分数理论和某些特殊不定方程。 是定义在正整数…

【DP】mobiusp正在创作乐曲

输入样例1&#xff1a; 5 2 1 7 7 1 3 输出样例1&#xff1a; 2 输入样例2&#xff1a; 10 3 2 5 6 4 4 5 7 3 5 6 输出样例2&#xff1a; 1 #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; typede…

遥遥领先!TinyEngine 低代码引擎更新升级!AI 已成功部署!

官网更新 1. 协议规范优化更新 协议规范交互优化&#xff0c;能够在一页里面自由切换&#xff0c;提高用户体验&#xff0c;后端SDK文档字段描述补齐&#xff0c;助力开发者自助进行服务端开发。 2.使用手册全新改版 去掉之前的学院课程&#xff0c;新设计新分类让结构一目了…