C++编码优化之减少冗余拷贝或赋值
C++编码优化之减少冗余拷贝或赋值临时变量目前遇到的一些产生临时变量的情况:函数实参、函数返回值、隐式类型转换、多余的拷贝。
1. 函数实参这点应该比较容易理解,函数参数,如果是实参传递的话,函数体里的修改并不会影响调用时传入的参数的值。那么函数体里操作的对象肯定是函数调用的过程中产生出来的。
那么这种情况我们该怎么办呢?
如果 callee 中确实要修改这个对象,但是 caller 又不想 callee 的修改影响到原来的值,那么这个临时变量就是必须的了,不需要也没办法避免。
如果 callee中根本没有修改这个对象,或者 callee 中这个参数本身就是 const 型的,那么将实参传递改为引用传递是个不错的选择(如果是基本类型的函数实参,则没有必要改为引用),可以减少一个临时变量而且不会带来任何损失。
另外,推荐一个静态代码检查工具 cppcheck,这个工具可以提示非基本类型的 const 实参改为引用。
2. 函数返回值(返回对象)函数返回值的情况比较复杂,因为编译器在这方面做了很多优化,编译器优化到何种程度我也没追根究底研究过。
在没开任何优化选项的时候,gcc 也优化了一 ...
C语言中三块难啃的硬骨头
C语言中三块难啃的硬骨头C语言在嵌入式学习中是必备的知识,审核大部分操作都要围绕C语言进行,而其中有三块“难啃的硬骨头”几乎是公认级别的。
0x01 指针指针公认最难理解的概念,也是让很多初学者选择放弃的直接原因。
指针之所以难理解,因为指针本身就是一个变量,是一个非常特殊的变量,专门存放地址的变量,这个地址需要给申请空间才能装东西,而且因为是个变量可以中间赋值,这么一倒腾很多人就开始犯晕了,绕不开弯了。C语言之所以被很多高手所喜欢,就是指针的魅力,中间可以灵活的切换,执行效率超高,这点也是让小白晕菜的地方。
指针是学习绕不过去的知识点,而且学完C语言,下一步紧接着切换到数据结构和算法,指针是切换的重点,指针搞不定下一步进行起来就很难,会让很多人放弃继续学习的勇气。
指针直接对接内存结构,常见的C语言里面的指针乱指,数组越界根本原因就是内存问题。在指针这个点有无穷无尽的发挥空间。很多编程的技巧都在此集结。
指针还涉及如何申请释放内存,如果释放不及时就会出现内存泄露的情况,指针是高效好用,但不彻底搞明白对于有些人来说简直就是噩梦。
在概念方面问题可以参见此前推文《对于C语言指针最详尽的 ...
一起探索C++类内存分布
一起探索C++类内存分布C++ 类中内存分布具体是怎么样,尤其是C++中含有继承、虚函数、虚拟继承以及菱形继承等等情况下。
由于在linux下没有windows下显示直观,我们采用vs2015进行调试。
部署环境
我们在 属性->C/C++ ->命令行 -> /d1 reportSingleClassLayoutXXX ,XXX表示类名;
单个基础类
12345678class Base{private: int a; int b;public: void test();};
内存分布:
12345class Base size(8): +-- - 0 | a 4 | b +-- -
总结:我们发现普通类的内存分布是根据声明的顺序进行的,成员函数不占用内存。
基础类+继承类
12345678910111213141516class Base{ int a; int b;public: void test();};class Divide :public Base{public: ...
C++内存管理
C++内存管理内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,因此要想成为C++高手,内存管理一关是必须要过的,除非放弃C++,转到Java或者C#,他们的内存管理基本是自动的,当然你也放弃了自由和对内存的支配权,还放弃了C++超绝的性能。本期专题将从内存管理、内存泄漏、内存回收这三个方面来探讨C++内存管理问题。
1. 内存管理伟大的Bill Gates 曾经失言:
640K ought to be enough for everybody — Bill Gates 1981
程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。
1.1 C++内存管理详解1.1.1 内存分配方式1.1.1.1 分配方式简介在C++中,内存分成5个区,他们分别是栈、堆、自由存 ...
C++ 使用 chrono 库处理日期和时间
C++ 使用 chrono 库处理日期和时间C++11 中提供了日期和时间相关的库 chrono,通过 chrono 库可以很方便地处理日期和时间,为程序的开发提供了便利。chrono 库主要包含三种类型的类:时间间隔duration、时钟clocks、时间点time point。
1. 时间间隔 duration1.1 常用类成员duration表示一段时间间隔,用来记录时间长度,可以表示几秒、几分钟、几个小时的时间间隔。duration 的原型如下:
12345// 定义于头文件 <chrono>template< class Rep, class Period = std::ratio<1>> class duration;
ratio 类表示每个时钟周期的秒数,其中第一个模板参数 Num 代表分子,Denom 代表分母,该分母值默认为 1,因此,ratio 代表的是一个分子除以分母的数值,比如:ratio<2> 代表一个时钟周期是 2 秒,ratio<60 > 代表一分钟,ratio<60*60 & ...
C/C++ 关于 cJson 库的使用
C/C++ 关于 cJson 库的使用关于 Json 这种数据格式,在前面已经做了详细的介绍 Json 的格式和用途,在项目开发过程中我们需要针对不同的语言使用不同的库对 Json 格式的数据进行解析,下面给大家介绍一个基于 C 语言的 Json 库 – cJson。cJSON 是一个超轻巧,携带方便,单文件,简单的可以作为 ANSI-C 标准的 JSON 解析器。
cJSON 是一个开源项目,github 下载地址:
https://github.com/DaveGamble/cJSON
cJSON,目前来说,主要的文件有两个,一个 cJSON.c 一个 cJSON.h。使用的时候,将头文件 include 进去即可。
如果是在 Linux 操作系统中使用,编译 到时候需要添加数学库 libm.so,如下所示:
1gcc *.c cJSON.c -lm
1. cJSON 结构体在 cJSON.h 中定义了一个非常重要的结构体 cJSON,想要熟悉使用 cJSON 库函数可从 cJSON 结构体入手,cJSON 结构体如下所示:
123456789typedef ...
C++后台
C++后台学习篇:一、一个项目入门C++足以:CPlusPlusThings.CPlusPlusThings 是国人开源一个 C++ 学习项目。它系统地将 C++ 学习分为了【基础进阶】、【实战系列】、【C++2.0 新特性】、【设计模式】和【STL 源码剖析】、【并发编程】、【C++ 惯用法】、【学习课程】、【工具】、【拓展】。
作为一个全面系统的 C++ 学习项目,CPlusPlusThings 是优秀的,它合理地安排了 10 Days 的实战部分,在实战中了解语法和函数用法,唯一不足的是,在注释部分有些不尽人意,对部分新手程序员并不是很友好。
CPlusPlusThings C++那些事 (light-city.club)
二、C++实现的算法合集:C-Plus-PlusC-Plus-Plus 是收录用 C++ 实现的各种算法的集合,并按照 MIT 许可协议进行授权。这些算法涵盖了计算机科学、数学和统计学、数据科学、机器学习、工程等各种主题。除外,你可能会发现针对同一目标的多个实现使用不同的算法策略和优化。
C-Plus-Plus
三、进阶指南:CppTemplateTu ...
C++编译期多态与运行期多态
C++编译期多态与运行期多态前言今日的C++不再是个单纯的“带类的C”语言,它已经发展成为一个多种次语言所组成的语言集合,其中泛型编程与基于它的STL是C++发展中最为出彩的那部分。在面向对象C++编程中,多态是OO三大特性之一,这种多态称为运行期多态,也称为动态多态;在泛型编程中,多态基于template(模板)的具现化与函数的重载解析,这种多态在编译期进行,因此称为编译期多态或静态多态。在本文中,我们将了解:
什么是运行期多态
什么是编译期多态
它们的优缺点在哪
运行期多态运行期多态的设计思想要归结到类继承体系的设计上去。对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些功能声明为虚接口(虚函数),然后由子类继承基类去重写这些虚接口,以实现子类特有的具体功能。典型地我们会举下面这个例子:
123456789101112131415161718192021222324252627282930313233343536class Animal{public : virtual void shout() = 0;};class ...
虚基类
虚基类1、使用virtual修饰
基类是虚的时候静止信息通过中间类传递给基类
需要显示的调用所需的基类构造函数
1.为什么要引入虚基类?在类的继承中,如果我们遇到这种情况:“B和C同时继承A,而B和C都被D继承”在此时,假如A中有一个函数fun()当然同时被B和C继承,而D按理说继承了B和C,同时也应该能调用fun()函数。这一调用就有问题了,到底是要调用B中的fun()函数还是调用C中的fun()函数呢?在C++中,有两种方法实现调用:(注意:这两种方法效果是不同的)
使用作用域标识符来唯一表示它们比如:B::fun()另一种方法是定义虚基类,使派生类中只保留一份拷贝。作用域标识符表示例子:
1234567891011121314151617181920212223242526272829#include<iostream>using namespace std;class base{ public: base(){a=5;cout<<"base="<<a<<endl;} ...
C++ 八股文(一)
C++ 八股文(一)多态什么是多态,有什么用C++ 多态有两种:静态多态(早绑定)、动态多态(晚绑定)。静态多态是通过函数重载实现的;动态多态是通过虚函数实现的。
定义:“一个接口,多种方法”,程序在运行时才决定要调用的函数。
实现:C++ 多态性主要是通过虚函数实现的,虚函数允许子类重写 override(注意和 overload 的区别,overload 是重载,是允许同名函数的表现,这些函数参数列表/类型不同)。
注:多态与非多态的实质区别就是函数地址是静态绑定还是动态绑定。如果函数的调用在编译器编译期间就可以确定函数的调用地址,并产生代码,说明地址是静态绑定的;如果函数调用的地址是需要在运行期间才确定,属于动态绑定。
目的:接口重用。封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。
用法:声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。
用一句话概括:在基类的函数前加上 virtual 关键字,在派生类中重写该函数,运行时将会根据对象的实际类 ...