这是bert hubert的系列文章,旨在帮助c代码人快速了解c++实用的新特性。原文链接:https://berthub.eu/
这可能是最后的第5部分,我们将介绍现代C++中一些最强大的功能:“完美”的引用计数和std::move概念。请注意,本篇引入了一些非常不熟悉的概念,所以阅读起来可能会比前面的部分更困难。
std::move
内存通常是决定程序速度和可靠性的最重要因素。现在的CPU往往比其连接的RAM快得多,所以防止不必要的复制和内存碎片可以提供数量级的速度提升。
C++的作者非常清楚这一点,并提供了使对象能够“就地”传递或构造的功能,从而节省了大量内存带宽。
这些技术中大多数需要一些思考,但我们将从一个几乎无形的技术开始,它解释了一些C代码通过重新编译为C++而变快的原因。
思考以下代码:
struct Object { // many fields }; Object getObject(size_t i) { Object obj; // retrieve object #i return obj; } int main() { Object o = getObject(271828); }
有经验的C程序员会被告诫不要这样做,从K&R的光荣页面开始。“通过栈传递结构会导致不必要的复制”。
相反,我们会传递一个指向Object的指针,仔细地将其重置为默认状态,然后填充它。
Object
在C中,编译器不允许像上面这样优化代码,并且在从getObject返回时会复制struct Object。然而,在C++中,不仅允许编译器进行优化,实际上所有编译器都会进行优化。实际上,Object o在调用方的栈上构造并填充,没有复制发生。
getObject
struct Object
Object o
这使得这样的代码能够高效:
Vector getAll(); // "Vector" from part 3 .. auto all = getAll(); // returns millions of Objects 我们会在后面看到:C++是如何显式的转换所有权而不是拷贝。 智能指针 在第2部分中,我们接触了智能指针。我们也注意到内存泄漏是每个项目的祸根,可能是用纯C编写的最令人头痛的事情。我知道的每个C(和C++)程序员都至少花了一个完整的周期来追踪一个难以察觉的内存泄漏。 这些问题非常大,以至于大多数现代编程语言决定承担大量的开销来实现垃圾收集(GC)。当GC工作时,它是惊人的,尤其是最近,开销现在至少是可管理的。但截至2018年,所有环境仍在为GC运行造成的停顿所苦,这些停顿总是恰恰发生在你不希望发生的时候。公平地说,这是一个非常困难的问题,尤其是当涉及许多线程时。 因此,C++没有实现垃圾收集。相反,有一些明智选择的智能指针可以执行自己的清理。在第2部分中,我们将std::shared\_ptr描述为“最符合用户期待”的智能指针,这是正确的。 然而,这样的魔法并非免费的。如果我们“查看”std::shared_ptr内部,它承载了大量的管理工作。首先当然是对所包含对象的实际指针。然后是引用计数,它需要始终以原子方式更新和检查。接下来,还可能有一个自定义析构函数。出于良好的理由,这些元数据本身是动态分配的(在堆上)。所以虽然std::shared_ptr的sizeof可能只有16字节(在64位系统上),但它实际上使用了更多内存。在一个具体的测试中,std::shared_ptr平均使用了47字节的内存。 问题是:我们能做得更好吗? 初识: std::unique_ptr 当C++采用其初始标准化形式时,通用引用计数指针的开销是众所周知的。当时,定义了一个古怪的智能指针std::auto_ptr,但结果证明在1998年的C++中不可能创建一些有用的东西。创建“完美的智能指针”需要C++ 2011才提供的功能。 首先,让我们试试一些简单的事情: std::unique_ptr testUnique; uint32_t* testRaw; std::shared_ptr testShared; cout << "sizeof(testUnique):\t" << sizeof(testUnique) << endl; cout << "sizeof(testRaw):\t" << sizeof(testRaw) << endl; cout << "sizeof(testShared):\t" << sizeof(testShared) << endl; 输出如下: sizeof(testUnique): 8 sizeof(testRaw): 8 sizeof(testShared): 16 您看到的没错。std::unique_ptr与“原始”指针相比没有开销。事实上,通过一些明智的转换,您可以发现它包含的除您放入其中的指针外什么也没有。这是零开销。 用法如下: void function() { auto uptr = std::make_unique(42); cout << *uptr << endl; } // uptr contents get freed here 第一行可以表示为: std::unique_ptr uptr = std::unique_ptr(new uint32_t(42)); 通常,对于智能指针,总是优先选择std::make_*形式。对于std::shared_ptr,它将两个分配合并为一个,这在CPU周期和内存消耗方面都有优势。_值得注意的是,std::unique_ptr是一个智能指针,但它不是一个通用的引用计数指针。或者,更准确地说,始终只有一个地方拥有std::unique_ptr。这就是为什么没有开销的魔力:没有引用计数要存储,它总是“1”。 std::unique_ptr仅在离开作用域或被重置或替换时进行清理。要访问智能指针的内容,可以取消引用它(使用*或->),也可以在需要内部指针时使用get()方法。智能指针也可以“unset”在这种情况下,评估为“假”: std::unique_ptr iptr; auto p = [](const auto& a) { cout << "pointer is " << (a ? "" : "not ") << "set\n"; }; p(iptr); cout << (void*) iptr.get() << endl; iptr = std::make_unique(12); p(iptr); iptr.reset(); p(iptr); 结果如下: pointer is not set 0 pointer is set pointer is not set 编译器不允许我们拷贝“std::unique_ptr”,但是却允许我们“move”它。 std::unique_ptr uptr2; uptr2 = uptr; // error about 'deleted constructor' uptr2 = std::move(uptr); // works 因为简单的拷贝会导致unique变为non-unique,两个ptr指向一个实例。那么move到底做了什么? std::move SmartFP 是RAII的一个实例。我们可以这样用它: int main() { try { string line; SmartFP sfp("/etc/passwd", r"); stringfgets(line, sfp.d_fp); // simple wrapper // do stuff } catch(std::exception& e) { cerr << "Fatal error: " << e.what() << endl; } } SmartFP底层只不过是fopen和fclose的封装。它也会对fopen的错误抛出异常。RAII的好处在于它保证文件描述符不会泄漏,即使在错误条件下也是如此。 在第2部分中,我们还注意到,按定义,SmartFP存在一个问题。当它超出作用域时,它执行fclose,但是如果有人复制了我们的SmartFP实例怎么办?然后我们会关闭同一个FILE指针两次,这非常糟糕。加入移动构造函数: struct SmartFP { SmartFP(const char* fname, const char* mode) { d_fp = fopen(fname, mode); if(!d_fp) throw std::runtime_error("Can't open file: " + stringerror()); } SmartFP(SmartFP&& src) // move constructor. Note "&&" { d_fp = src.d_fp; src.d_fp = 0; } ~SmartFP() { if(d_fp) fclose(d_fp); } FILE* d_fp{0}; }; move constructor是非常重要的一个环节,它高速C++类不能被拷贝,只能被移动。move的语义就是所有权的转移。 SmartFP sfp("/etc/passwd", "ro"); cout << (void*) sfp.d_fp << endl; // prints a pointer SmartFP sfp2 = sfp; // error SmartFP sfp2 = std::move(sfp); // transfer! cout << (void*) sfp.d_fp << endl; // prints 0 cout << (void*) sfp2.d_fp << endl; // prints same pointer 当此代码运行时,我们在第一行创建的FILE指针将完全关闭一次fclose。这是因为在移动过程中,FILE*被设置为零,在析构函数中,我们确保不要关闭0。 move在返回时会自动执行: SmartFP getTmpFP() { // get tmp name return SmartFP(tmp, "w"); } ... SmartFP fp = getTmpFP(); 此外,c++标准容器也是用move的,根据移动语义原地构造元素: vector vec; vec.emplace_back("move.cc", "r"); emplace_back的参数全部转发给SmartFP构造函数,后者直接在std::vector中构造实例,全部不需要复制。在填充大容器时,这可以产生巨大的差异。 注意,如果需要,一个类可以同时具有移动构造函数和常规构造函数。一个很好的例子是所有的C++标准容器,包括std::string。这为您提供了选择 – 进行实际复制还是转移所有权。 智能指针和多态性 我们将东西存储为指针的主要原因是为了受益于多态性。指针的缺点当然是内存管理,所以如果智能指针可以与基类和派生类互操作,那就太好了。确实,它们可以。 基于我们在第3部分的Event类: std::deque> eventQueue; eventQueue.push_back(std::make_unique("1.2.3.4")); eventQueue.push_back(std::make_unique()); for(const auto& e : eventQueue) { cout << e->getDescription() << endl; } 这一切都按预期工作,当容器超出作用域时,eventQueue的内容会被清理。 使用多态类时,确保不存在~析构函数,或者将其声明为虚拟的。否则std::unique_ptr将调用基类析构函数。有关更多详细信息,请参阅第3部分。 placement new auto ptr = new SmartFP("/etc/passwd", "ro"); 这会做两件事: 分配内存以存储SmartFP实例 使用该内存调用SmartFP构造函数 通常这就是我们需要的。然而,有时候我们的内存来自其他地方,但我们仍然希望在上面构造对象。进入 placement new。这是一个来自PowerDNS dumresp实用程序的实际用例: std::atomic* g_counter; auto ptr = mmap(NULL, sizeof(std::atomic), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); g_counter = new(ptr) std::atomic(); for(int i = 1; i < atoi(argv[3]); ++i) { if(!fork()) break; } 这使用mmap来分配将与任何子进程共享的内存,然后使用花哨的placement new语法在该共享内存中构造一个std::atomic实例。 然后代码fork了argv[3]中描述的进程数。在所有这些进程中,一个简单的++(*g_counter)工作后,所有进程都将更新相同的计数器。 基于这种技术,可以创建高效且易于使用的进程间通信库,例如Boost Interprocess。 mmap允许在进程间共享内存区域。placement new使得可以直接在mmap的共享内存中构造对象,而不需要额外的内存分配和复制。结合使用二者,可以避免不必要的内存操作,提高多进程程序的性能。 其他的一些建议 一些一般建议 许多现代C++项目只会有少数显式调用new或delete(或malloc/free)。审计这几个调用很容易。仅将手动内存分配限于您真正必须的情况。 对于其余情况,如果可以的话,请使用std::unique_ptr,如果不行,请使用std::shared_ptr。请注意,您可以有效地将std::unique_ptr转换为std::shared_ptr,可以这样改变主意: auto unique = std::make_unique("test"); std::shared_ptr shared = std::move(unique); 此外,std::unique_ptr也可以release()它拥有的指针,这意味着它不会被自动delete。 以低廉的代价将std::unique_ptr转换为std::shared_ptr或原始指针的易用性,意味着函数可以返回std::unique_ptr并让所有人满意。 对于移动构造函数,理解这个不太熟悉的构造是有价值的。 代表资源的类(如socket、文件描述符、数据库连接)自然适合具有移动构造函数,因为这使它们的语义与这些资源的工作方式紧密匹配:应该确切地打开和关闭一次,并且应当在合适的时机。 总结 内存分配很困难,C++提供的各种智能指针使其更容易。 std::shared_ptr很奢侈但带来包袱,std::unique_ptr通常就足够好了,完全没有开销。 C++努力避免对象的不必要复制,添加移动构造函数使这一点明确。通过使用std::move,可以将std::unique_ptr实例存储在容器中,这既安全又快速。 智能指针简化了内存管理,unique_ptr用于独占所有权,shared_ptr用于共享所有权。 移动语义通过转移资源所有权优化性能,避免复制开销。 结合移动语义和右值引用,可以安全高效地在容器中存储unique_ptr。 C++提供了各种机制来尽量避免不必要的内存分配和对象复制。明智地使用可以写出高性能和安全的代码。 你可能感兴趣的:(c++,c语言,java) Java实现SQLite数据库克隆 行云斡 Java实战演练数据库javasqlite Java实现SQLite数据库克隆题目要求过程整理分步实现完整代码改进空间转载请注明出处题目要求Writeaprogram(inJavaandusingJDBC)thatclonesaSQLitedatabaseandproducesatextual“backup”ofthecontents.ThistextualbackupshouldconsistofSQLstatementsthatwill NO.13十六届蓝桥杯备战|条件操作符|三目操作符|逻辑操作符|!|&&|||(C++) ChoSeitaku 蓝桥杯备考蓝桥杯c++职场和发展 条件操作符条件操作符介绍条件操作符也叫三⽬操作符,需要接受三个操作数的,形式如下:exp1?exp2:exp3条件操作符的计算逻辑是:如果exp1为真,exp2计算,exp2计算的结果是整个表达式的结果;如果exp1为假,exp3计算,exp3计算的结果是整个表达式的结果。这种三⽬操作符和if语句的逻辑⾮常相似,就是根据exp1的结果来选择执⾏exp2,或者exp3。⼀般使⽤在简单的逻辑判断中。练 【C/C++】创建链表例题学习 奇变偶不变0727 c语言链表开发语言 题目:函数接口定义:voidinput();该函数利用scanf从输入中获取学生的信息,并将其组织成单向链表。链表节点结构定义如下:structstud_node{intnum;/*学号*/charname[20];/*姓名*/intscore;/*成绩*/structstud_node*next;/*指向下个结点的指针*/};单向链表的头尾指针保存在全局变量head和tail中。输入为若干个学生 JAVA学习-类型信息.动态代理 守护者170 java学习java学习开发语言 在Java中,动态代理是一种通过在运行时生成代理对象来拦截对目标对象的访问的技术。Java中的动态代理基于反射机制,利用反射生成代理类来实现对目标对象的代理。一、Java中的动态代理主要有两种方式:基于接口的动态代理和基于类的动态代理。它们的特点如下:1.基于接口的动态代理(JDK动态代理):基于接口的动态代理要求目标对象实现一个或多个接口。JDK动态代理使用'java.lang.reflect. Java黑皮书课后题第11章:11.2(Person Student Employee Faculty Staff类)设计一个名为Person的类及其两个名为Student和Employee的子类 有只程序猿 Java黑皮书课后题java Java黑皮书课后题第11章:11.2(PersonStudentEmployeeFacultyStaff类)题目缺陷UML图代码Test02_MyDate.java:用于参考的MyDateTest02_Person.java:Person类Test02_Student.java:Student类Test02_Employee.java:Employee类Test02_Faculty.java:F 2020-10-09 weixin_45660257 笔记 java学习集合的目标1.会使用集合存储数据2.会遍历集合,把数据取出来3.掌握每种集合的特性集合框架的学习方法方式1.学习顶层:学习顶层接口,抽象类中共性的方法,所有的子类创建对象使用Collection接口定义的是所有的单列集合中共性的方法所有的单列集合都可以使用共性的方法没有带索引的方法继承:子类共性抽取形成父类(接口)List接口1.有序的集合(存储和取出元素顺序相同)2.允许存储重复的元 android 串口通信代码 weixin_44693887 移动开发androidjava开发语言androidstudio 以下是在Android平台上实现串口通信的代码示例。要实现串口通信,需要先创建一个类来处理串口通信。下面是一个名为SerialPortHelper的串口帮助类的示例:importandroid.content.Context;importandroid.os.Handler;importandroid.os.Message;importjava.io.FileDescriptor;importja Android RXjava实现子线程做耗时操作,比new Thread和handler更香 weixin_44693887 androidrxjava 1.首先是在build.gradle里面引用下面两个库implementation‘io.reactivex.rxjava2:rxandroid:2.0.1’implementation‘io.reactivex.rxjava2:rxjava:2.0.7’2.创建CompositeDisposable。CompositeDisposable是一个存放Disposable的集合,它是一个容器Comp android liveData更新UI数据 weixin_44693887 android 1.创建LiveData的javaBean对象publicclassModelBeanextendsLiveData{privateintflag;privateStringtime;privateStringbatteryStr;privateintbattery;//蓝牙连接状态privateintresourceId;privateBooleanisConnected;privateStri Java实现日志全链路追踪.精确到一次请求的全部流程 王会举 javalog4j 广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向.实现效果如下:一次查询即可找到所有关键信息.不再被多线程日志进行困扰了.1:日志打印框架log4j->logbacklogback是springboot默认自带的 Java EE 8 API.chm下载 007MDT java-ee 自己在官网下载的文档,然后用绿色版的easychm制作的chm文件,英文版支持索引查找下载链接自己在网上找了好久都是csdn积分下载的对我这种新人属实不友好,所以就自己动手了,如果有帮助到你记得评论支持一下噢 JDK8 升级至 JDK17 打包问题分析 Resean0223 实际项目问题汇总日常问题解决javamavenjdk 一、概述近日为了满足客户需求将项目的jdk版本由原先的1.8升级至17,整个过程比较顺利,但是在maven打包时出现了报错。报错信息为:(程序包sun.security.util已在模块java.base中声明,但该模块未将它导出到未命名模块)二、问题分析引起该问的原因是因为从jdk9开始使用module模块化引用的结构,包时存在的,只是我们在打包时没有将该模块引入并声明。关于module模块化的 链接阿里云IoT Edge设备接入SDK Java版教程 郑微殉 链接阿里云IoTEdge设备接入SDKJava版教程linkedge-thing-access-sdk-javaLinkIoTEdge提供的设备接入驱动开发SDK(Java版本),帮助用户在LinkIoTEdge上快速开发自定义协议设备接入Java语言驱动。项目地址:https://gitcode.com/gh_mirrors/li/linkedge-thing-access-sdk-java1. 【课程设计】Java EE SSM 试卷管理系统 鱼弦 课程设计java-eejava JavaEESSM试卷管理系统简介试卷管理系统是一个用于教育机构、培训中心等单位的在线考试和评估工具。该系统帮助教师管理考试题目、生成试卷,并将试卷导出为Word文档。应用使用场景学校与教育机构:用于日常测验、期中和期末考试。企业培训:用于员工技能测试和评估。在线教育平台:用于提供学生练习题和模拟考试。原理解释架构系统基于JavaEE开发,采用了Spring、SpringMVC和MyBatis(S AJAX 与 ASP:现代 Web 开发的关键技术 csbysj2020 开发语言 AJAX与ASP:现代Web开发的关键技术引言在当今的Web开发领域,AJAX(AsynchronousJavaScriptandXML)和ASP(ActiveServerPages)是两项至关重要的技术。AJAX允许网页在不重新加载整个页面的情况下,与服务器交换数据和更新部分网页内容。而ASP则是一种服务器端脚本环境,用于动态生成交互性网页。本文将深入探讨AJAX和ASP的技术细节、应用场景以及 Java高级特性 - Java反射 Ssaty. java开发语言java-ee 第1关:了解Class对象本关任务:实现获取Class对象的三种方式packagestep1;/***学员任务文件*/publicclassReflect_stu{publicstaticvoidmain(String[]args){System.out.println< Java 项目集成 DeepSeek,亮点项目(包成功) 代码星辰阁(公众号同名) springboot编程springbootdeepseek人工智能java 获取DeepSeekAPI并搭建简易问答Java应用的完整步骤:“代码星辰阁”公众号有完整代码获取DeepSeekAPIKey访问DeepSeek官网:打开DeepSeek开放平台,点击右上角的“开放平台”。注册或登录账号:新注册账号通常会赠送一定数量的免费tokens。创建APIKey:在左侧菜单中点击APIKeys。点击“创建APIKey”,为APIKey命名(如“test”),然后创建。系统 C++之线程池(Thread Pool) 画个逗号给明天" 开发语言c++ 1.介绍线程池是一种并发编程的设计模式,用于管理和复用多个线程。以避免频繁创建和销毁线程的开销。线程池的核心思想是预先创建一组线程,并将任务分配给这些线程执行,从而提高程序的性能和资源利用率。2.线程池的核心组件一个经典的线程池包含以下组件:(1)任务队列(TaskQueue):用于存储待执行的任务。通常是一个线程安全的队列(如queue>)。(2)工作线程(workerThreads):一组预先 JAVA EE初阶 - 预备知识(一) 2025年一定要上岸 java-ee 一、管道在计算机编程和操作系统环境中,输入、输出和错误管道是用于在不同进程或程序之间传递数据和信息的重要机制,下面分别对它们进行详细介绍:输入管道(StandardInput,stdin)定义:输入管道是进程获取外部数据的通道。它允许一个进程从其他进程、用户输入设备(如键盘)或文件中接收数据。当一个进程启动时,操作系统通常会为其分配一个标准输入流,进程可以通过读取这个输入流来获取所需的数据。工作原 打印金字塔总结(c/c++) shixiexunnie 算法入门c语言c++算法 打印金字塔总结(c/c++)前事不忘,后事之师;在做循环结构时惊觉前几题几乎都是打印space或*或字符、数字打印的图像,看了看没啥人做这种基础题的盘点总结,秉承节流(时间)的精神也就为类己的萌新规范化此类题目,亦当作后续牛客算法题解之预热变尽人间、君山一点、自古如今写到后面才觉应先写方法用诸后例:1.明确画图要素:是单独的*、space加*还是space加其他符号如字母数字2.明确需要几个for 深入浅出:8种常见排序算法的效率对比与应用场景(JAVA) 技术小泽 排序算法算法数据结构java后端 5.归并排序归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。算法核心逻辑如下分割数组首先,把数组分成两半,然后分别对这两半继续进行分割,直到每一部分只有一个元素。每次分割都通过计算中间索引mid=(left+right)/2来进行。排序当数组 jQuery.ajax weixin_48357623 前端jqueryajax前端 下面是关于FetchAPI、umi-request、jQuery.ajax和axios的对比表格:FetchAPIumi-requestjQuery.ajaxaxios技术基础基于Promise的现代浏览器API基于fetch的封装,提供统一API和请求层治理原生JavaScript中的XMLHttpRequest封装基于Promise的HTTP客户端,封装XMLHttpRequest使用场景适用 java数据结构 mobi_数据结构:Java语言描述(第2版) pdf epub mobi txt 下载 周佩茹 java数据结构mobi 数据结构:Java语言描述(第2版)pdfepubmobitxt下载图书介绍☆☆☆☆☆刘小晶,杜选,朱蓉,杜卫锋编下载链接在页面底部发表于2021-02-24类似图书点击查看全场最低价出版社:清华大学出版社ISBN:9787302389446版次:2商品编码:11678255品牌:清华大学包装:平装丛书名:21世纪高等学校规划教材·计算机科学与技术开本:16开出版时间:2015-04-01用纸:胶 数据结构java实验 刘小晶_清华大学出版社-图书详情-《数据结构实例解析与实验指导——Java语言描述》... 季退思 数据结构java实验刘小晶 本书是《数据结构——Java语言描述》(ISBN:9787302243236,清华大学出版社)的配套教学辅助用书,也是考研的复习用书。本书打破了传统的单一辅导书的编写形式,从整个课程能力培养和课程实践能力培养分析入手,以“重基础,求创新”为目标,针对基本数据结构和两种常用操作进行知识的归纳和提炼,对典型实例进行清晰的剖析,然后通过大量实例对知识进行巩固和应用。实验内容的安排由浅入深,层次分 springboot+vue使用EasyCaptcha实现简单验证码 ueanaIU潇潇子 springbootvue.js图形验证码EasyCaptcha 一、实现效果springboot使用EasyCaptcha实现简单验证码,更多api和用法可以去github上查看EasyCaptcha:Java图形验证码,支持gif、中文、算术等类型,可用于JavaWeb、JavaSE等项目。二、实现步骤1、导入依赖com.github.whvcseeasy-captcha1.6.2org.openjdk.nashornnashorn-core15.4我使用的 C语言 二维数组3*4矩阵 求最大值 函数封装 要长脑子了 o.0 c语言c++算法 参考如下:#includevoidintputArry(intarry[][4],intihang,intjlie){inti;intj;for(i=0;i c++ vscode 第三方库_使用VSCode和CMake构建跨平台的C/C++开发环境 杨易之君 c++vscode第三方库 日前在学习制作LearnOpenGL教程的实战项目Breakout游戏时,希望能将这个小游戏开发成跨平台的,支持在多个平台运行。工欲善其事必先利其器,首先需要做的自然是搭建一个舒服的跨平台C/C++开发环境,所以这篇文章主要就是记录环境搭建的整个过程,踩到的一些坑,以及对应的解决办法。正文开始之前,先来阐述几个问题为什么选择使用VSCode实在用不习惯VisualStudio(也可能是用的太少了T error C2511: 'Teacher_Cadre::Teacher_Cadre(std::string,int,char,std::string,std::string,std::string, 小凡1991 VisualStudio调试相关C++visualstudio 学习C++遇到的错误:errorC2511:'Teacher_Cadre::Teacher_Cadre(std::string,int,char,std::string,std::string,std::string,std::string,float)':overloadedmemberfunctionnotfoundin'Teacher_Cadre'原因:重载的函数实现与类中定义的函数变量类型 Linux系统编程:网络编程与Socket通信详解 Dev-Kilig Linuxlinux网络运维 引言网络编程是Linux系统编程的核心内容之一,而Socket是实现网络通信的基石。无论是Web服务器、即时通讯工具还是分布式系统,都依赖于Socket进行数据传输。本文将深入讲解Socket编程的基本概念,并通过C语言实现一个完整的TCP客户端-服务器通信示例,帮助初学者掌握网络编程的核心技能。一、Socket编程基础1.1什么是Socket?Socket(套接字)是网络通信的端点,用于在不同主 ✨JMH(Java Microbenchmark Harness)✨ 魔镜前的帅比 java开发语言 JMH(JavaMicrobenchmarkHarness)是一个专门用于编写、运行和分析Java微基准测试的工具。它由OpenJDK团队开发,旨在提供精确的基准测试结果,避免常见的基准测试陷阱,如JVM的优化、即时编译(JIT)等影响。核心知识点基准测试的目的基准测试用于测量代码的性能,通常是在微秒或纳秒级别。它可以帮助开发者识别性能瓶颈,优化代码。JMH的特点精确性:JMH通过多次迭代和预热来 枚举的构造函数中抛出异常会怎样 bylijinnan javaenum单例 首先从使用enum实现单例说起。 为什么要用enum来实现单例? 这篇文章( http://javarevisited.blogspot.sg/2012/07/why-enum-singleton-are-better-in-java.html)阐述了三个理由: 1.enum单例简单、容易,只需几行代码: public enum Singleton { INSTANCE; CMake 教程 aigo C++ 转自:http://xiang.lf.blog.163.com/blog/static/127733322201481114456136/ CMake是一个跨平台的程序构建工具,比如起自己编写Makefile方便很多。 介绍:http://baike.baidu.com/view/1126160.htm 本文件不介绍CMake的基本语法,下面是篇不错的入门教程: http: cvc-complex-type.2.3: Element 'beans' cannot have character Cb123456 springWebgis cvc-complex-type.2.3: Element 'beans' cannot have character Line 33 in XML document from ServletContext resource [/WEB-INF/backend-servlet.xml] is i jquery实例:随页面滚动条滚动而自动加载内容 120153216 jquery <script language="javascript"> $(function (){ var i = 4;$(window).bind("scroll", function (event){ //滚动条到网页头部的 高度,兼容ie,ff,chrome var top = document.documentElement.s 将数据库中的数据转换成dbs文件 何必如此 sqldbs 旗正规则引擎通过数据库配置器(DataBuilder)来管理数据库,无论是Oracle,还是其他主流的数据都支持,操作方式是一样的。旗正规则引擎的数据库配置器是用于编辑数据库结构信息以及管理数据库表数据,并且可以执行SQL 语句,主要功能如下。 1)数据库生成表结构信息: 主要生成数据库配置文件(.conf文 在IBATIS中配置SQL语句的IN方式 357029540 ibatis 在使用IBATIS进行SQL语句配置查询时,我们一定会遇到通过IN查询的地方,在使用IN查询时我们可以有两种方式进行配置参数:String和List。具体使用方式如下: 1.String:定义一个String的参数userIds,把这个参数传入IBATIS的sql配置文件,sql语句就可以这样写: <select id="getForms" param Spring3 MVC 笔记(一) 7454103 springmvcbeanRESTJSF 自从 MVC 这个概念提出来之后 struts1.X struts2.X jsf 。。。。。 这个view 层的技术一个接一个! 都用过!不敢说哪个绝对的强悍! 要看业务,和整体的设计! 最近公司要求开发个新系统! Timer与Spring Quartz 定时执行程序 darkranger springbean工作quartz 有时候需要定时触发某一项任务。其实在jdk1.3,java sdk就通过java.util.Timer提供相应的功能。一个简单的例子说明如何使用,很简单: 1、第一步,我们需要建立一项任务,我们的任务需要继承java.util.TimerTask package com.test; import java.text.SimpleDateFormat; import java.util.Date; 大端小端转换,le32_to_cpu 和cpu_to_le32 aijuans C语言相关 大端小端转换,le32_to_cpu 和cpu_to_le32 字节序 http://oss.org.cn/kernel-book/ldd3/ch11s04.html 小心不要假设字节序. PC 存储多字节值是低字节为先(小端为先, 因此是小端), 一些高级的平台以另一种方式(大端) Nginx负载均衡配置实例详解 avords [导读] 负载均衡是我们大流量网站要做的一个东西,下面我来给大家介绍在Nginx服务器上进行负载均衡配置方法,希望对有需要的同学有所帮助哦。负载均衡先来简单了解一下什么是负载均衡,单从字面上的意思来理解就可以解 负载均衡是我们大流量网站要做的一个东西,下面我来给大家介绍在Nginx服务器上进行负载均衡配置方法,希望对有需要的同学有所帮助哦。 负载均衡 先来简单了解一下什么是负载均衡 乱说的 houxinyou 框架敏捷开发软件测试 从很久以前,大家就研究框架,开发方法,软件工程,好多!反正我是搞不明白! 这两天看好多人研究敏捷模型,瀑布模型!也没太搞明白. 不过感觉和程序开发语言差不多, 瀑布就是顺序,敏捷就是循环. 瀑布就是需求、分析、设计、编码、测试一步一步走下来。而敏捷就是按摸块或者说迭代做个循环,第个循环中也一样是需求、分析、设计、编码、测试一步一步走下来。 也可以把软件开发理 欣赏的价值——一个小故事 bijian1013 有效辅导欣赏欣赏的价值 第一次参加家长会,幼儿园的老师说:"您的儿子有多动症,在板凳上连三分钟都坐不了,你最好带他去医院看一看。" 回家的路上,儿子问她老师都说了些什么,她鼻子一酸,差点流下泪来。因为全班30位小朋友,惟有他表现最差;惟有对他,老师表现出不屑,然而她还在告诉她的儿子:"老师表扬你了,说宝宝原来在板凳上坐不了一分钟,现在能坐三分钟。其他妈妈都非常羡慕妈妈,因为全班只有宝宝 包冲突问题的解决方法 bingyingao eclipsemavenexclusions包冲突 包冲突是开发过程中很常见的问题: 其表现有: 1.明明在eclipse中能够索引到某个类,运行时却报出找不到类。 2.明明在eclipse中能够索引到某个类的方法,运行时却报出找不到方法。 3.类及方法都有,以正确编译成了.class文件,在本机跑的好好的,发到测试或者正式环境就 抛如下异常: java.lang.NoClassDefFoundError: Could not in 【Spark七十五】Spark Streaming整合Flume-NG三之接入log4j bit1129 Stream 先来一段废话: 实际工作中,业务系统的日志基本上是使用Log4j写入到日志文件中的,问题的关键之处在于业务日志的格式混乱,这给对日志文件中的日志进行统计分析带来了极大的困难,或者说,基本上无法进行分析,每个人写日志的习惯不同,导致日志行的格式五花八门,最后只能通过grep来查找特定的关键词缩小范围,但是在集群环境下,每个机器去grep一遍,分析一遍,这个效率如何可想之二,大好光阴都浪费在这上面了 sudoku solver in Haskell bookjovi sudokuhaskell 这几天没太多的事做,想着用函数式语言来写点实用的程序,像fib和prime之类的就不想提了(就一行代码的事),写什么程序呢?在网上闲逛时发现sudoku游戏,sudoku十几年前就知道了,学生生涯时也想过用C/Java来实现个智能求解,但到最后往往没写成,主要是用C/Java写的话会很麻烦。 现在写程序,本人总是有一种思维惯性,总是想把程序写的更紧凑,更精致,代码行数最少,所以现 java apache ftpClient bro_feng java 最近使用apache的ftpclient插件实现ftp下载,遇见几个问题,做如下总结。 1. 上传阻塞,一连串的上传,其中一个就阻塞了,或是用storeFile上传时返回false。查了点资料,说是FTP有主动模式和被动模式。将传出模式修改为被动模式ftp.enterLocalPassiveMode();然后就好了。 看了网上相关介绍,对主动模式和被动模式区别还是比较的模糊,不太了解被动模 读《研磨设计模式》-代码笔记-工厂方法模式 bylijinnan java设计模式 声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ package design.pattern; /* * 工厂方法模式:使一个类的实例化延迟到子类 * 某次,我在工作不知不觉中就用到了工厂方法模式(称为模板方法模式更恰当。2012-10-29): * 有很多不同的产品,它 面试记录语 chenyu19891124 招聘 或许真的在一个平台上成长成什么样,都必须靠自己去努力。有了好的平台让自己展示,就该好好努力。今天是自己单独一次去面试别人,感觉有点小紧张,说话有点打结。在面试完后写面试情况表,下笔真的好难,尤其是要对面试人的情况说明真的好难。 今天面试的是自己同事的同事,现在的这个同事要离职了,介绍了我现在这位同事以前的同事来面试。今天这位求职者面试的是配置管理,期初看了简历觉得应该很适合做配置管理,但是今天面 Fire Workflow 1.0正式版终于发布了 comsci 工作workflowGoogle Fire Workflow 是国内另外一款开源工作流,作者是著名的非也同志,哈哈.... 官方网站是 http://www.fireflow.org 经过大家努力,Fire Workflow 1.0正式版终于发布了 正式版主要变化: 1、增加IWorkItem.jumpToEx(...)方法,取消了当前环节和目标环节必须在同一条执行线的限制,使得自由流更加自由 2、增加IT Python向脚本传参 daizj python脚本传参 如果想对python脚本传参数,python中对应的argc, argv(c语言的命令行参数)是什么呢? 需要模块:sys 参数个数:len(sys.argv) 脚本名: sys.argv[0] 参数1: sys.argv[1] 参数2: sys.argv[ 管理用户分组的命令gpasswd dongwei_6688 passwd NAME: gpasswd - administer the /etc/group file SYNOPSIS: gpasswd group gpasswd -a user group gpasswd -d user group gpasswd -R group gpasswd -r group gpasswd [-A user,...] [-M user,...] g 郝斌老师数据结构课程笔记 dcj3sjt126com 数据结构与算法 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< yii2 cgridview加上选择框进行操作 dcj3sjt126com GridView 页面代码 <?=Html::beginForm(['controller/bulk'],'post');?> <?=Html::dropDownList('action','',[''=>'Mark selected as: ','c'=>'Confirmed','nc'=>'No Confirmed'],['class'=>'dropdown',]) linux mysql fypop linux enquiry mysql version in centos linux yum list installed | grep mysql yum -y remove mysql-libs.x86_64 enquiry mysql version in yum repositoryyum list | grep mysql oryum -y list mysql* install mysq Scramble String hcx2013 String Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively. Below is one possible representation of s1 = "great": 跟我学Shiro目录贴 jinnianshilongnian 跟我学shiro 历经三个月左右时间,《跟我学Shiro》系列教程已经完结,暂时没有需要补充的内容,因此生成PDF版供大家下载。最近项目比较紧,没有时间解答一些疑问,暂时无法回复一些问题,很抱歉,不过可以加群(334194438/348194195)一起讨论问题。 ----广告----------------------------------------------------- nginx日志切割并使用flume-ng收集日志 liyonghui160com nginx的日志文件没有rotate功能。如果你不处理,日志文件将变得越来越大,还好我们可以写一个nginx日志切割脚本来自动切割日志文件。第一步就是重命名日志文件,不用担心重命名后nginx找不到日志文件而丢失日志。在你未重新打开原名字的日志文件前,nginx还是会向你重命名的文件写日志,linux是靠文件描述符而不是文件名定位文件。第二步向nginx主 Oracle死锁解决方法 pda158 oracle select p.spid,c.object_name,b.session_id,b.oracle_username,b.os_user_name from v$process p,v$session a, v$locked_object b,all_objects c where p.addr=a.paddr and a.process=b.process and c.object_id=b. java之List排序 shiguanghui list排序 在Java Collection Framework中定义的List实现有Vector,ArrayList和LinkedList。这些集合提供了对对象组的索引访问。他们提供了元素的添加与删除支持。然而,它们并没有内置的元素排序支持。 你能够使用java.util.Collections类中的sort()方法对List元素进行排序。你既可以给方法传递 servlet单例多线程 utopialxw 单例多线程servlet 转自http://www.cnblogs.com/yjhrem/articles/3160864.html 和 http://blog.chinaunix.net/uid-7374279-id-3687149.html Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的 按字母分类: ABCDEFGHIJKLMNOPQRSTUVWXYZ其他
我们会在后面看到:C++是如何显式的转换所有权而不是拷贝。
在第2部分中,我们接触了智能指针。我们也注意到内存泄漏是每个项目的祸根,可能是用纯C编写的最令人头痛的事情。我知道的每个C(和C++)程序员都至少花了一个完整的周期来追踪一个难以察觉的内存泄漏。
这些问题非常大,以至于大多数现代编程语言决定承担大量的开销来实现垃圾收集(GC)。当GC工作时,它是惊人的,尤其是最近,开销现在至少是可管理的。但截至2018年,所有环境仍在为GC运行造成的停顿所苦,这些停顿总是恰恰发生在你不希望发生的时候。公平地说,这是一个非常困难的问题,尤其是当涉及许多线程时。
因此,C++没有实现垃圾收集。相反,有一些明智选择的智能指针可以执行自己的清理。在第2部分中,我们将std::shared\_ptr描述为“最符合用户期待”的智能指针,这是正确的。
std::shared\_ptr
然而,这样的魔法并非免费的。如果我们“查看”std::shared_ptr内部,它承载了大量的管理工作。首先当然是对所包含对象的实际指针。然后是引用计数,它需要始终以原子方式更新和检查。接下来,还可能有一个自定义析构函数。出于良好的理由,这些元数据本身是动态分配的(在堆上)。所以虽然std::shared_ptr的sizeof可能只有16字节(在64位系统上),但它实际上使用了更多内存。在一个具体的测试中,std::shared_ptr平均使用了47字节的内存。
std::shared_ptr
sizeof
问题是:我们能做得更好吗?
当C++采用其初始标准化形式时,通用引用计数指针的开销是众所周知的。当时,定义了一个古怪的智能指针std::auto_ptr,但结果证明在1998年的C++中不可能创建一些有用的东西。创建“完美的智能指针”需要C++ 2011才提供的功能。
std::auto_ptr
首先,让我们试试一些简单的事情:
std::unique_ptr testUnique; uint32_t* testRaw; std::shared_ptr testShared; cout << "sizeof(testUnique):\t" << sizeof(testUnique) << endl; cout << "sizeof(testRaw):\t" << sizeof(testRaw) << endl; cout << "sizeof(testShared):\t" << sizeof(testShared) << endl;
输出如下:
sizeof(testUnique): 8 sizeof(testRaw): 8 sizeof(testShared): 16
您看到的没错。std::unique_ptr与“原始”指针相比没有开销。事实上,通过一些明智的转换,您可以发现它包含的除您放入其中的指针外什么也没有。这是零开销。
std::unique_ptr
用法如下:
void function() { auto uptr = std::make_unique(42); cout << *uptr << endl; } // uptr contents get freed here
第一行可以表示为:
std::unique_ptr uptr = std::unique_ptr(new uint32_t(42));
通常,对于智能指针,总是优先选择std::make_*形式。对于std::shared_ptr,它将两个分配合并为一个,这在CPU周期和内存消耗方面都有优势。_值得注意的是,std::unique_ptr是一个智能指针,但它不是一个通用的引用计数指针。或者,更准确地说,始终只有一个地方拥有std::unique_ptr。这就是为什么没有开销的魔力:没有引用计数要存储,它总是“1”。
std::make_*
std::unique_ptr仅在离开作用域或被重置或替换时进行清理。要访问智能指针的内容,可以取消引用它(使用*或->),也可以在需要内部指针时使用get()方法。智能指针也可以“unset”在这种情况下,评估为“假”:
unset
std::unique_ptr iptr; auto p = [](const auto& a) { cout << "pointer is " << (a ? "" : "not ") << "set\n"; }; p(iptr); cout << (void*) iptr.get() << endl; iptr = std::make_unique(12); p(iptr); iptr.reset(); p(iptr);
结果如下:
pointer is not set 0 pointer is set pointer is not set
编译器不允许我们拷贝“std::unique_ptr”,但是却允许我们“move”它。
move
std::unique_ptr uptr2; uptr2 = uptr; // error about 'deleted constructor' uptr2 = std::move(uptr); // works
因为简单的拷贝会导致unique变为non-unique,两个ptr指向一个实例。那么move到底做了什么?
unique
non-unique
ptr
SmartFP 是RAII的一个实例。我们可以这样用它:
SmartFP
int main() { try { string line; SmartFP sfp("/etc/passwd", r"); stringfgets(line, sfp.d_fp); // simple wrapper // do stuff } catch(std::exception& e) { cerr << "Fatal error: " << e.what() << endl; } }
SmartFP底层只不过是fopen和fclose的封装。它也会对fopen的错误抛出异常。RAII的好处在于它保证文件描述符不会泄漏,即使在错误条件下也是如此。
fopen
fclose
在第2部分中,我们还注意到,按定义,SmartFP存在一个问题。当它超出作用域时,它执行fclose,但是如果有人复制了我们的SmartFP实例怎么办?然后我们会关闭同一个FILE指针两次,这非常糟糕。加入移动构造函数:
FILE
struct SmartFP { SmartFP(const char* fname, const char* mode) { d_fp = fopen(fname, mode); if(!d_fp) throw std::runtime_error("Can't open file: " + stringerror()); } SmartFP(SmartFP&& src) // move constructor. Note "&&" { d_fp = src.d_fp; src.d_fp = 0; } ~SmartFP() { if(d_fp) fclose(d_fp); } FILE* d_fp{0}; };
move constructor是非常重要的一个环节,它高速C++类不能被拷贝,只能被移动。move的语义就是所有权的转移。
move constructor
SmartFP sfp("/etc/passwd", "ro"); cout << (void*) sfp.d_fp << endl; // prints a pointer SmartFP sfp2 = sfp; // error SmartFP sfp2 = std::move(sfp); // transfer! cout << (void*) sfp.d_fp << endl; // prints 0 cout << (void*) sfp2.d_fp << endl; // prints same pointer
当此代码运行时,我们在第一行创建的FILE指针将完全关闭一次fclose。这是因为在移动过程中,FILE*被设置为零,在析构函数中,我们确保不要关闭0。
FILE*
move在返回时会自动执行:
SmartFP getTmpFP() { // get tmp name return SmartFP(tmp, "w"); } ... SmartFP fp = getTmpFP();
此外,c++标准容器也是用move的,根据移动语义原地构造元素:
vector vec; vec.emplace_back("move.cc", "r");
emplace_back的参数全部转发给SmartFP构造函数,后者直接在std::vector中构造实例,全部不需要复制。在填充大容器时,这可以产生巨大的差异。
emplace_back
std::vector
注意,如果需要,一个类可以同时具有移动构造函数和常规构造函数。一个很好的例子是所有的C++标准容器,包括std::string。这为您提供了选择 – 进行实际复制还是转移所有权。
std::string
我们将东西存储为指针的主要原因是为了受益于多态性。指针的缺点当然是内存管理,所以如果智能指针可以与基类和派生类互操作,那就太好了。确实,它们可以。
基于我们在第3部分的Event类:
std::deque> eventQueue; eventQueue.push_back(std::make_unique("1.2.3.4")); eventQueue.push_back(std::make_unique()); for(const auto& e : eventQueue) { cout << e->getDescription() << endl; }
这一切都按预期工作,当容器超出作用域时,eventQueue的内容会被清理。
eventQueue
使用多态类时,确保不存在~析构函数,或者将其声明为虚拟的。否则std::unique_ptr将调用基类析构函数。有关更多详细信息,请参阅第3部分。
auto ptr = new SmartFP("/etc/passwd", "ro");
这会做两件事:
分配内存以存储SmartFP实例
使用该内存调用SmartFP构造函数
通常这就是我们需要的。然而,有时候我们的内存来自其他地方,但我们仍然希望在上面构造对象。进入 placement new。这是一个来自PowerDNS dumresp实用程序的实际用例:
placement new
PowerDNS dumresp
std::atomic* g_counter; auto ptr = mmap(NULL, sizeof(std::atomic), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); g_counter = new(ptr) std::atomic(); for(int i = 1; i < atoi(argv[3]); ++i) { if(!fork()) break; }
这使用mmap来分配将与任何子进程共享的内存,然后使用花哨的placement new语法在该共享内存中构造一个std::atomic实例。
mmap
std::atomic
然后代码fork了argv[3]中描述的进程数。在所有这些进程中,一个简单的++(*g_counter)工作后,所有进程都将更新相同的计数器。
fork
argv[3]
++(*g_counter)
基于这种技术,可以创建高效且易于使用的进程间通信库,例如Boost Interprocess。
Boost Interprocess
mmap允许在进程间共享内存区域。placement new使得可以直接在mmap的共享内存中构造对象,而不需要额外的内存分配和复制。结合使用二者,可以避免不必要的内存操作,提高多进程程序的性能。
一些一般建议
许多现代C++项目只会有少数显式调用new或delete(或malloc/free)。审计这几个调用很容易。仅将手动内存分配限于您真正必须的情况。
对于其余情况,如果可以的话,请使用std::unique_ptr,如果不行,请使用std::shared_ptr。请注意,您可以有效地将std::unique_ptr转换为std::shared_ptr,可以这样改变主意:
auto unique = std::make_unique("test"); std::shared_ptr shared = std::move(unique);
此外,std::unique_ptr也可以release()它拥有的指针,这意味着它不会被自动delete。
release()
delete
以低廉的代价将std::unique_ptr转换为std::shared_ptr或原始指针的易用性,意味着函数可以返回std::unique_ptr并让所有人满意。
对于移动构造函数,理解这个不太熟悉的构造是有价值的。
代表资源的类(如socket、文件描述符、数据库连接)自然适合具有移动构造函数,因为这使它们的语义与这些资源的工作方式紧密匹配:应该确切地打开和关闭一次,并且应当在合适的时机。
内存分配很困难,C++提供的各种智能指针使其更容易。
std::shared_ptr很奢侈但带来包袱,std::unique_ptr通常就足够好了,完全没有开销。
C++努力避免对象的不必要复制,添加移动构造函数使这一点明确。通过使用std::move,可以将std::unique_ptr实例存储在容器中,这既安全又快速。
智能指针简化了内存管理,unique_ptr用于独占所有权,shared_ptr用于共享所有权。
unique_ptr
shared_ptr
移动语义通过转移资源所有权优化性能,避免复制开销。
结合移动语义和右值引用,可以安全高效地在容器中存储unique_ptr。
C++提供了各种机制来尽量避免不必要的内存分配和对象复制。明智地使用可以写出高性能和安全的代码。