c# out原理 ref_移植贪吃蛇——从C#到C++

欢迎参与讨论,转载请注明出处。

前言

  因为某些机缘巧合,引起了我对C++的重视。一时兴起,决定将两年前用Unity写的Snake进行移植。经过两周的抽空,总算是完成了。项目采用现代C++标准编写,采用CMake构建,图形库为SDL。由于本次的重点不在于图形这块,所以没有使用原版的素材,采用矩形代替。

  在工程实现上除了基本的业务外,还实现了C#的event以及的Unity的GameObject与Component。

  本文将从C#开发者的角度出发比较C++的不同点,最后总结其思想。由于本人在此之前从未有C++的工程经验,对于许多特性在此之前也是一知半解,对于一些事物的理解若有误还请指教。

低成本封装

首先最引我瞩目的便是C++的参数传递,形如这般的函数:

void Init(const string& title, int width, int height);

  由于C++的引用参数string&性质,将值传入时不会发生拷贝,而是等于直接使用原变量。可以有效降低封装抽象的成本,加上const字段是为使得形如"123"这样的常量区对象也能传入。

  当然这在C#也并不是没有,ref便是如此。但这在C#并不会下意识去用,毕竟在C++若是不用指针或引用作为参数的话可是会直接拷贝新对象的,而在C#直接使用也不会造成很大的负担(值类型直接拷贝,引用类型用指针)。

  其次便是C++的内联函数了,作为函数宏的替代品之一。可以在编译时将函数展开为具体的内容,节省了一次函数调用的消耗。但内联函数需写在头文件中,若是关联项多,修改后便会增加编译时长。且展开量过大也会增大代码量,增加编译时长。但不失为一个降低封装成本的手段。

明确的内存

其次与C#最大的不同便是对象的创建了,C++有着以下两种形式:

A a = A();
A* a = new A();

了解C++的自然晓得,前者在当前内存域下申请,后者在堆申请。而在C#则隐去了这个细节,而是设立固定的规则:

  • 引用对象使用指针,原则上在堆申请,若对象的生命周期存在于申请的函数里,则在栈申请——是为逃逸分析
  • 值对象在当前内存域下申请,且由于不是指针,变量传递会产生拷贝。除非使用ref、in、out等参数关键字。

  而C++的内存申请机制则带来了明确感,如在函数里申请生命周期只存在函数里的对象,需要明确的使用A a = A();方式。且在构建类的时候,对于那些不使用A* a = new A();创建方式的成员变量,其内存占用是明确的,在类对象申请内存的时候会一并申请,即这些成员变量在内存布局上可能是连续的。从这点来说可比C#要牛逼多了。

相似的容器

  在容器方面,C++与C#大体看起来是相似的,当然在API的爽度而言还是C#更胜一筹(C++17拉近了不少)。但实际上还是存在一些细节上的不同,就比如我们常用的Key-Value容器:C++的std::map与C#的Dictionary在实现乃至功能上就不一样。实际上std::map对应C#的应该是SortedDictionary:它们都是基于红黑树实现,都是有序存储的表。而Dictionary则是基于哈希实现的,即我们俗称的哈希表,与之对应的是std::unordered_map。

  通过命名能看出两种语言在这方面的倾向性:红黑树占用的内存更小,但查找和删除的时间复杂度都是O(logn),而哈希查找和删除的时间复杂度都是O(1)。实际使用的时候感觉还是得权衡利弊,不能贪图方便就一直用一套。std::set与HashSet这边也是类似的对应,以此类推。

  在序列容器方面的对应倒是工整:std::vector对应List,都是不断扩容的数组容器。链表方面则是std::list对应LinkedList。但std::array却无对应了,硬要说的话就是与C#的原生数组对应,毕竟这个容器出现的意义就是弥补与C语言兼容的原生数组。

  顺带一提,在使用std::vector时由于会出现扩容复制的问题,需要考虑好成员对象的拷贝方案,乃至于内存泄漏的问题。

智能的指针

  内存管理是所有编程语言都无法绕开的点,绝大多数编程语言对于堆内存的管理都是采用垃圾回收的方式。而在C++的鸿蒙时代则与C语言一样,需要手动管理指向堆内存的指针。尽管也有std::auto_ptr这样的东西,但在功能上还不够全面。而手动管理内存将难以解决对象在多处被引用时将如何安全销毁的问题,为了实现这种机制也得做出不少妥协。

  所幸随着时代的发展,现代C++迎来了智能指针,它基于引用计数的规则,将裸指针包装起来,当符合销毁条件后便可自动回收。智能指针有着几种具体的类实现,而其中最常用的是std::share_ptr,当它持有指针时将增加计数,反之同理将减少计数,最终归0销毁。但其较之垃圾回收有个致命的缺陷:相互引用时将一直保持计数,无法销毁。为此C++引入了std::weak_ptr:它不会增加计数,在计数归0时持有指针也随之销毁。如此对于相互引用的情况下,分清主次,合理分配share_ptr与weak_ptr即可解决无法销毁的问题。

  智能指针在使用上总有一种外挂的感觉,需要成体系的去使用。不如内置的垃圾回收式语言来的方便,且写起来还是有一定的心智负担(相互引用),不过在性能而言较之垃圾回收更为优越(回收对象与时机都很明确,且是被动进行的)。

模板与泛型

C++的模板与C#的泛型表面上用起来很是相似,实则有所不同。以下对比两者的差异:

template<class T, int x> // C++支持模板参数,可填写整型或指针
GenericList<T> where T : Employee // C#使用System.Object不支持的方法时,需进行类型约束指定基类
// 这么骚的操作见过么?
void f(int x);template <class ... Args>
void Do(Args... args) {f(args ...);
};

  从实际使用体验与两者的命名可以看出,「模板」的本质是参数化代码生成,而「泛型」则是类型参数化。即泛型只是模板功能的一部分而已。模板能实现的其他功能,在C#则以其他方式代替了(如变长参数params)。

后记

  从以上种种便能看出C++与C#在设计哲学上的不同,C#通过约束开发者行为从而达到更稳定健壮的结果,哪怕会失去一定的性能与灵活性,而C++则更依赖开发者自身的素质(如C++支持多重继承而C#仅仅支持单类+多接口继承)。

  从个人的使用体验来看,现代C++并非不能作为业务开发语言。只是对开发者的素质要求较之一般语言更高,从招聘成本与项目稳定性而言是个问题。如此来看,除非有必要的性能敏感且需要一定封装的核心层(如游戏引擎),否则用C + 脚本语言或者C#/Java这类可上可下的语言是个更好的选择。

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

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

相关文章

seata 如何开启tcc事物_分布式事务Seata-TCC源码分析

为了更好理解分布式事务&#xff0c;首先提出一个问题&#xff1a;假设数据库中有两个表ta&#xff0c;tb&#xff0c;我们要分别更改ta表中的ra记录和tb表中的rb记录&#xff0c;但要求ra和rb记录都修改成功&#xff0c;才认为此次操作时成功&#xff0c;或者需要失败回滚。针…

helm安装mysql_helm安装配置

简介helm是kubernetes的包管理工具&#xff0c;用于简化部署和管理 Kubernetes 应用。用来管理charts——预先配置好的安装包资源。Helm和charts的主要作用&#xff1a;应用程序封装版本管理依赖检查便于应用程序分发helm是一个C/S框架的软件&#xff0c;helm相当于一个客户端&…

promise的三种状态_一.Promise中核心逻辑的实现

首先看一下Promise代码&#xff1a;let promise new Promise((resolve,reject)>{resolve(成功);//reject(失败); }) promise.then(val>{console.log(val); },reason>{console.log(reason); })我们根据以上的一个简单的用例&#xff0c;得到Promise类的最主要的核心逻辑…

mysql如何定位到数据_如何快速定位当前数据库消耗CPU最高的sql语句?

概述如果是Oracle数据库我们可以很容易通过sql来定位到当前数据库中哪些消耗CPU高的语句&#xff0c;而mysql数据库可以怎么定位呢&#xff1f;这里用一个简单例子说明下...主要是了解如何定位的思路&#xff0c;具体看官网介绍..参考&#xff1a;https://www.percona.com/blog…

当当elastic-job docker快速部署_[小Z课堂]-docker 快速部署 elasticsearch 和 kibana,一键部署...

各位小伙伴&#xff0c;小Z课堂来袭&#xff0c;每天只需看三分钟&#xff0c;你就能用docker 快速部署各种环境。今天就用docker 来部署 elasticsearch 和 kibana。docker的入门请上度娘学习&#xff0c;这里直接进入实战。拉镜像镜像版本&#xff1a;base image&#xff1a;U…

xtrabackup备份mysql5.7_【 xtrabackup】CentOS7.x上基于 MySQL 5.7.x的XtraBackup 安装与备份还原...

MySQL的XtraBackup 备份与恢复https://shockerli.net/post/xtrabackup-backup-recovery-mysqlPercona XtraBackup 备份原理与实践http://www.unixfbi.com/349.htmlXtraBackup备份恢复模拟实践https://blog.51cto.com/13178102/2151512Percona XtraBackup 安装介绍篇https://www…

数字有维度, 质数可追寻

摘要 用数轴的点表示数, 实际是把数的几何意义单一 化, 把所有实数同等化. 在研究素数的问题上, 应该挖掘数的 更多几何意义, 就正自然数而言, 不同区间的数, 几何意义是 不相同的, 对应的点是不同空间的点, 具有多样化的. 寻找质 数, 就是设法把不同空间的 1 维数 (质数) 找出…

局域网聊天程序 java MySQL_课内资源 - 基于JAVA的局域网聊天软件的设计与实现(仿制QQ)...

一、系统分析1.1 问题描述客户端实现简易版的局域网聊天器实现富文本内容聊天智能聊天机器人群发消息传送文件等功能服务器端实现群发通知管理聊天线程1.2 系统功能分析客户端功能登陆注册发送表情消息发送文本消息截取图片图片处理震动效果发送文件群发消息设置聊天文本样式服…

北工大一拟录取女研究生在网络发不当言论,已被网友举报!

近日&#xff0c;北工大一拟录取女研究生在自己的社交平台发表不当的言论。随后&#xff0c;其言论引起网友的热议。>>>>对于网友的质疑&#xff0c;其通过微博发文称&#xff0c;要“开小号专门打拳”。当天夜里&#xff0c;有网友通过其微博的公开的考研信息&…

mysql微服务查询问题_【mysql】微服务架构下跨服务查询的聚合有什么好的方案?...

微服务架构中&#xff0c;每个服务都有自己的独立数据库。然而现在有个需求&#xff0c;需要生成一张实时的报表&#xff0c;该报表包含两个服务的数据。如服务A&#xff0c;服务B。B中仅包含A的主键id作为关联。而此报表的搜索条件包含A服务实体中的字段也包含B服务实体中的字…

mnist数据集svm python_python支持向量机分类MNIST数据集

支持向量机在高维或无限维空间中构造超平面或超平面集合&#xff0c;其可以用于分类、回归或其他任务。直观来说&#xff0c;分类边界距离最近的训练数据点越远越好&#xff0c;因为这样可以缩小分类器的泛化误差。调用sklearn.svm的svc函数&#xff0c;将MNIST数据集进行分类&…

mysql触发器可以使用正则表达式_SQL 正则表达式及mybatis中使用正则表达式

这篇文章主要介绍了SQL 正则表达式及mybatis中使用正则表达式的方法&#xff0c;非常不错&#xff0c;具有一定的参考借鉴价值,需要的朋友可以参考下mysql 提供的模式匹配的其他类型是使用扩展正则表达式。当你对这类模式进行匹配测试时&#xff0c;使用REGEXP和NOT REGEXP操作…

python代码200行左右_200行Python代码实现2048

import cursesfrom random import randrange,chiocefrom collections import defaultdictactions[Up,Left,Down,Right,Restart,Exit]letter_codes[ord(ch) for ch in WASDRQwasdrq]action_dictdict(zip(letter_codes,actions*2))def main(stdscr):def init():#重置游戏棋盘game…

python将excel导入mysql_Python将Excel数据自动导入MySQL,python,实现,excel,到,中

废话不多说&#xff0c;下面附上代码。# -*- coding: utf-8 -*-"""Created on Mon Apr 20 14:18:49 2020author: admin"""import osimport pandas as pd#import cx_Oracle as cxfrom sqlalchemy import create_engineimport pymysqlfile_name[]#…

presto java_Presto Jdbc

Presto Jdbc标签(空格分隔)&#xff1a; Presto一&#xff0c; 建立连接传统的JDBC方式类似&#xff0c;建立PrestoConnection”连接“&#xff0c;并且通过unwrap方法将connection转换为PrestoConnection。实际上是赋值一些基本信息&#xff0c;并且建立新的OkHttpClient。Str…

计算机二级java上机_计算机二级JAVA上机试题及答案

2016年9月计算机等级考试正在紧张复习中&#xff0c;为帮助大家进一步复习java&#xff0c;yjbys小编为大家带来最新java上机试题及答案如下&#xff1a;1. 基本操作(1小题&#xff0c;计30分)注意&#xff1a;下面出现的“考生文件夹”均为%USER%在考生文件夹中存有文件名为Ja…

java divide 用法_java中BigDecimal加减乘除基本用法

Java在java.math包中提供的API类BigDecimal&#xff0c;用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中&#xff0c;需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算&#xff0c;在商…

如何反映两条曲线的拟合精度_你知道850加工中心定位精度的检测有哪些吗?

你知道850加工中心定位精度的检测有哪些吗&#xff1f;定位精度在机械制造上指零件或刀具等实际位置与标准位置&#xff08;理论位置/理想位置&#xff09;之间的差距&#xff0c;其差距越小&#xff0c;说明精度越高。定位精度是零件加工精度得以保证的前提。XFL-850加工中心的…

java ee最新_从此再无 JavaEE,现在叫 JakartaEE

各位小伙伴,你们都知道这个消息吗&#xff1f;Java EE 正式改名为 Jakarta EE 了。以后小伙伴们自我介绍的时候又多了一种方式。(〃▽〃) &#xff1a;你是做什么的&#xff1f;(&#xffe3;▽&#xffe3;)~* &#xff1a;你好我是做 JakartaEE&#xff01;Σ(っД;)っ&#…

十二月份找工作好找吗_小儿推拿师工作好找吗?工资高吗?

小儿推拿师工作好找吗&#xff1f;会不会学成之后找不到工作?作为现在比较热门的一个医学类职业&#xff0c;小儿推拿师还是比较容易找工作的&#xff0c;现在基本一条街上能有不低于十家小儿推拿店&#xff0c;而这些店里面小儿推拿师只有两三个&#xff0c;后面孩子还有很多…