![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
编程(汇编/C/C++)
文章平均质量分 74
__Lemon__
这个作者很懒,什么都没留下…
展开
-
堆内存传递
下面一段关于GetMemory()的代码是面试时最容易出现的题目。发现自己在解释原理的时候,还是有点“拗口”, 就来总结一下吧。下例实际上涉及的就是传参的方式或堆内存的传递(堆内存靠指针来传递)。传参的方式:1.值 2.指针(如果变量本身就是一个指针,把此变量当作一个对象,就要传指针的指针?) 3.引用(实际就是传变量本身,不管变量是一个对象还是一个指针)详见代码注原创 2016-04-22 09:27:08 · 704 阅读 · 0 评论 -
实现一个简单的shared_ptr
在看《effective C++》第3章时,基本上都是auto_ptr和shared_ptr的原理与应用。auto_ptr和shared_ptr基本原理都是将构造好(new)的裸资源指针交给对象去打理,当对象释放时自动调用析构函数,在析构函数中delete裸资源指针;从而避免遗忘手动释放指针。auto_ptr通过拷贝构造或者通过=赋值后,原来的auto_ptr就失效了(裸资源指针赋值为0)原创 2016-05-30 14:22:59 · 1073 阅读 · 0 评论 -
类初始化列表
以前在写代码时用初始化列表,因为前辈们说效率更高,也没有去想为什么。最近看>Item4: 确保对象在使用前被初始化,恍然大悟。如果使用赋值的方式在构造函数中初始化“类成员变量”,会先调用这个“类成员变量”类的默认构造函数,再调用赋值函数。而使用初始化列表初始化“类成员变量”,只会调用这个“类成员变量”类的拷贝构造函数。“赋值方式初始化”比“初始化列表”多调用一次默认构造函数,对于数原创 2016-04-05 13:22:33 · 832 阅读 · 0 评论 -
避免返回对象内部构件的“句柄”
下面的一些想法来自《Effective C++》中的 Item 28: 避免返回对象内部构件的“句柄” 。避免返回对象内部构件的句柄(引用,指针,或迭代器(也算是指针))。如果返回对象内部构建的句柄(引用、指针),当对象先于内部句柄析构后,内部句柄会“空悬”。这里的“空悬”即指针无意义的指向,会引起堆内存无法释放。如果返回对象内部的对象,不会有问题,对象会自动析构。我想:不光要避免原创 2016-05-12 18:38:27 · 887 阅读 · 0 评论 -
访问类私有成员变量
下面列举了“非类成员”访问“类私有成员变量”的3种方法: 1.通过类公有成员函数set(), get()写、读私有成员; 2.通过类公有成员函数get()获取私有成员的指针或引用,对指针或引用操作; 3.通过友元。 方法1,3都是经常使用的,方法2有点意外(写这篇blog也是因为它);不管怎么说,方法2,3都破坏了类的封装性。#include原创 2016-05-12 18:03:20 · 2693 阅读 · 0 评论 -
虚继承
直入主题:为什么虚继承能够解决“菱形继承”?(阅读下文之前可参考下我之前总结的“虚函数的本质”和“多重继承”。)经过gdb调试,终于揭开了面纱。下例类结构: Base / \DerivedA DerivedB \ / Derived在非虚继承时,DerivedA和原创 2016-04-28 12:25:29 · 596 阅读 · 0 评论 -
C++隐藏和覆盖
重载、覆盖、隐藏有着“千丝万缕”的关系,很容易混淆,就简单梳理了一下。 隐藏覆盖范围基类与派生类基类与派生类关键点基类可以不为虚函数,也可以为虚函数基类必须为虚函数相同点基类中多个函数重载,一旦一个被子类隐藏,所有的都将被隐藏翻译 2015-03-31 16:02:12 · 1832 阅读 · 0 评论 -
拷贝构造函数
拷贝构造函数,常被称为X(X&)。拷贝构造函数的作用:1.传值;2.传返回值; 3.对象初始化赋值。当从一个“老对象”复制出一个“新对象”时,新对象将产生自己的内存空间,并且新对象具有和老对象一样的内存空间结构;老对象的变量(指针、数字、字符、字符串等定长类型)值都会被拷贝入新对象中。但是,如果老对象中有堆内存,在新对象中并不会复制堆内存,而是指向老对象的堆内存。这就是浅拷贝,原创 2015-04-03 17:06:26 · 994 阅读 · 0 评论 -
const应用2
之前总结了一篇const相关的文章“const使用小结”,在这里做点补充。 1.const可用于函数重载,见下例中的类成员函数:void out()和void out() const;2.函数后跟着const,表示:const的函数不能对其数据成员进行修改;3.const函数中,不能对其数据成员进行修改,但可以对其指针成员的“指向数据”修改;4.const的对象,不能引用非co原创 2016-03-29 14:16:11 · 649 阅读 · 0 评论 -
#define和typedef
在C/C++中,经常被问到#define和typedef的区别,我想,最大的区别是:#define为预处理指令,用它来定义常量(包括无参量与带参量),在编译的预处理阶段进行简单的替换typedef常用来定义一个已知类型、标识符或关键字的别名,在编译时如同定义变量的方法那样来声明一种类型。下面列举了一些具体的异同:原创 2014-08-08 13:22:10 · 885 阅读 · 0 评论 -
set_new_handler
之前,曾对new做了一些总结,详见"new的理解".在看《effective C++》第8章时,对内存分配有一些新的认识,这里主要讲一讲对set_new_handler的理解。当使用nothrow_t版的operator new时,如果不能满足一个内存分配请求,会返回一个NULL指针。void* operator new (std::size_t size, const std::原创 2016-06-12 16:39:14 · 1049 阅读 · 0 评论 -
C++ string小结1
1. C++ string是C++标准库的一部分 标准C++除了包含所有的标准C库外(其中有为支持类型安全而进行的少许增加与更改),还加进了自己特有的库,这些库比起标准C中的库,功能更加强大。可以说,它们的影响力几乎就等同于由C到C++的转变。 将string看作容器对象,它用迭代器来指示字符序列的开始与结尾。 STL中replace()算法的原创 2015-10-20 14:49:08 · 991 阅读 · 0 评论 -
运算符重载
在C++内置数据类型中(char,int,float,double等),每一种类型都可进行运算符操作,例如:加减乘除运算。对于用户自定义的数据类型,只能自己进行运算符重载,赋予它们类似内置数据类型加减乘除等的意义。相对于函数调用,运算符重载的目的是使程序更容易阅读,书写和理解。运算符重载虽然好用,但不能随便用,因为运算符重载赋予运算符在不同情况下的不同功能,滥用反而导致混乱。例如:原创 2016-09-13 16:22:13 · 720 阅读 · 0 评论 -
自定义类型转换函数
(本文参考自《More Effecitve C++》 Item5 谨慎定义类型转换函数)自定义类型转换函数有2种: 1.隐式类型转换运算符; 2.单参数构造函数。隐式类型转换运算符是一个成员函数:operator其后跟一个类型和符号;不用定义函数的返回类型,因为返回类型就是这个函数的名字。单参数构造函数是指只用一个参数即可以调用的构造函数。该函数可以是只定义了一个参数,也可以是虽定原创 2016-07-21 10:28:32 · 1643 阅读 · 0 评论 -
成员函数模板
在同一个模板的不同实例化之间没有继承关系(也不存在隐式转换关系);为什么呢? 以继承关系为例,当编译器遇到“派生类模板”的定义时,它知道它继承于"基类模板",但是T是一个模板参数,这个直到更迟一些才能被确定当"派生类模板"被实例化的时候。不知道T是什么,就没有办法知道“基类” 是什么样子的。 为了使具有继承关系(隐式转换关系)的类进行转换,必须在拷贝构造函数原创 2016-06-22 14:02:01 · 1027 阅读 · 0 评论 -
C语言基本数据类型及转换规则
C语言的基本数据类型;有点奇怪的是为什么float和double不用signed/unsigned修饰。符号属性长度属性基本型所占位数取值范围输入符举例输出符举例----char8-2^7 ~ 2^7-1%c%c、%原创 2014-05-08 16:04:13 · 4866 阅读 · 0 评论 -
什么时候使用引用
当必须指向一个对象并且不想改变其指向时,或者在重载操作符并为防止不必要的语义误解时,你应该使用引用;而在除此之外的其他情况下,则应使用指针。下面这个例子是引用指向一个对象并且不会改变其指向,这个“new出来的对象”只能被引用改变。关于在重载操作符并为防止不必要的语义误解时使用引用,参考《more effecitve c++》 Item 1。#include using nam原创 2016-07-13 10:32:21 · 2215 阅读 · 0 评论 -
不要对数组使用多态
在对数组进行传参使用多态时,程序会crash; 因为数组在移位至下一数据时,步长是形参(基类)的size,而不是指针实际指向数据类型(派生类)的size,所以会数组会移位至一个非法的地址。详见下例:有1点需要注意:如果Base和Derived类size大小一样(有相同的数据成员),不会crash。#include using namespace std;class Base原创 2016-07-13 09:35:00 · 1065 阅读 · 1 评论 -
定制new和delete
在看《effective C++》第8章(定制new和delete)时,发现自己对new和delete理解的并不是那么深刻。为什么要定制new和delete呢,因为在某些环境下(嵌入式),定制的new和delete效率会更高。我在之前的文章“重载new和delete检测内存泄漏”中也做过类似的总结。下面的例子中重载了class-specific new和class-specific原创 2016-06-14 10:26:13 · 643 阅读 · 0 评论 -
虚函数的本质
一直不明白虚函数的本质,在看了>之后,豁然开朗,下面就自己总结一下。虚函数之所以能够做到动态调用,是因为程序在执行阶段才确定调用,也就是晚绑定。而早绑定在编译阶段就已经确定下一步该调用哪个函数。那么晚绑定又是如何实现的呢?晚绑定的本质是:当实例化一个虚函数类对象时,编译器会生成一个VPTR指针和VTABLE表,VTABLE表中存放所有“虚函数地址”;VPTR指向VTABLE的首地址。不原创 2015-03-27 17:40:17 · 1460 阅读 · 0 评论 -
const使用小结
const VS enum和#define 在C++中,常量有3种表达方式:cosnt, enum和#define,这3种方式有什么不同呢?1. #define在编译预处理时进行数据替换,没有存储空间; enum是编译时常量,没有存储空间; const将会分配数据存储空间(取决于编译器是否进行constant propagation)。2. #define在de原创 2015-06-15 13:18:00 · 977 阅读 · 0 评论 -
“异常处理”学习小结
在我经历过的项目中,很少使用异常处理;对于问题的调试与追踪,基本上都是基于错误码和日志信息。 这里的学习总结来自于>和网络,有很多问题的理解还需要实践经验。在C语言中处理异常的3种方式: 1) 在函数中返回错误信息; 2) 使用标准C库中的信号处理系统,由函数signal()和raise()实现; 3) 使用标准C库中原创 2015-09-23 10:01:57 · 1912 阅读 · 1 评论 -
重载new和delete检测内存泄漏
内存泄漏就是new出来的内存没有通过delete合理的释放。重载new和delete检测内存泄漏原理是:在重载的new中记录内存分配情况,在重载的delete中删除内存分配记录,从而跟踪所有内存分配信息。下面代码的是在《Think in C++ V2》第2章中源码的例子基础上修改的。一点笔记来自《Think in C++ V2》中第2章:1. 断言是一个肯定语句,用来肯定显原创 2015-10-10 14:51:44 · 2289 阅读 · 1 评论 -
由sizeof和strlen想到的
一直以为自己理解了sizeof和strlen,当碰壁之后才发现自己理解的不够全面。sizeof是C/C++中的一元运算符(不可重载),用于计算任意数据类型(基本型、符合型)、对象、函数所占据的大小,单位是字节。 strlen是C标准库中函数,只能用于计算字符串的长度(遇'\0'终止,不包括'\0')。sizeof 类型,该类型所占的空间大小;sizeof 对象,对象的实际占用空间大原创 2014-09-18 10:45:30 · 792 阅读 · 0 评论 -
指针应用小结(一)
指针是C/C++中最灵活的变量,可随意指向任何内存地址,稍有不慎,就会造成程序崩溃,且很难找出原因。下面这道题,程序crash,一开始没找到原因,经过gdb调试之后,找到根本原因。原创 2014-09-23 15:17:03 · 1224 阅读 · 0 评论 -
日志宏定义
在编码过程中,我们通常需要打印日志来跟踪程序运行轨迹。这里定义了几个日志宏,包括以下功能:1.日志开关(关闭开关,日志将不在打印)2.日志级别,定义不同的宏,打印不同级别日志3.精确打印时间、文件、函数、行,变量值等。原创 2014-07-29 14:37:27 · 1903 阅读 · 0 评论 -
exit函数相关
程序退出的函数有:return(), exit(), _exit(), atexit(), on_exit(), abort(), pthread_exit()等。下面这个程序对退出函数做了个测试。#include#include#include#include#include //return将控制权移交给递归的前一级,直到最初的一级(main函数下),return才会终原创 2014-07-05 10:40:48 · 1028 阅读 · 0 评论 -
C++类默认函数
很久没看C++了,遇到了一道C++类相关试题,输出结果让我有点诧异,想了下,终于找到原因。 原题原创 2014-07-08 11:05:18 · 958 阅读 · 0 评论 -
main函数前后
1.main函数的原型为int main(int argc, char* argv[], char* env[]),可以打印出传入参数和环境变量。2.main函数的返回值虽然是int(占4个字节),但却只用了1个字节保存返回值。正确的返回值是0xreturn&0xff.在bash里执行echo $?查看程序退出码。3.main函数之前执行部分,全局变量构造函数,__attribute__(原创 2014-07-05 13:35:22 · 1257 阅读 · 3 评论 -
C++类型强转
数据类型强转,可以用C风格的强转和C++下的运算符强转。数据类型强转包括:内置对象和内置对象之间,自定义对象和自定义对象之间,指针(引用)之间,指针与对象之间,对象与指针之间,继承关系类之间。经过测试,具体强转规则有:1).C风格强转:C++把它保留了下来,以利于兼容;可对应一切C++运算符强转;有几种情况不能强转:自定义类型对象(无继承关系)之间不能强转;不能将父类对象转换为子类对象原创 2014-06-12 12:13:14 · 2171 阅读 · 0 评论 -
局部变量返回值
发现自己对返回局部变量值的理解有些误区,网上查了下资料,加上自己的测试,做点小总结。 函数的返回值可以是变量、常量、指针(地址)、引用。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。当返回值是局部变量时,实际上返回的是局部变量的拷贝。当返回值是局部变量指针时,返回的是指针的拷贝,由于变量值已经释放,指针指向的值是无效的值。当原创 2014-06-26 12:35:19 · 1712 阅读 · 0 评论 -
多态类型
接口的多种不同的实现方式即为多态。通俗点说一种类型可以应对多种类型的操作。在C/C++中有多态类型有指针、union、模板、void*;多态类型在作为接口时有数据保护和隐藏的效果。 指针:在具有继承关系的类中,通过将子类对象地址赋值给父类对象指针之后,父对象指针就可以根据当前赋值给它的子对象的特性以不同的方式执行。在C++中利用指针实现了面向对象语言的一个重要特性“多态”。函数原创 2014-05-09 14:41:29 · 2186 阅读 · 0 评论 -
栈内存学习
栈是一种数据结构,栈是一种思想(后进先出),栈应用于栈内存的分配。那么数据是如何存入栈中的呢?栈的存储方向是从高地址往低地址,栈底永远在栈的最高地址,栈顶随压栈、出栈动态移动,一直指向栈的最低地址。程序的运行实际上是不断的(变量声明、参数传递、函数调用、值返回)的过程。这个过程实际上就是一个压栈的过程。最先调用的函数内存地址是最高的,函数嵌套调用过程中,被调用函数内存地址逐级变小,原创 2014-05-08 16:38:55 · 1277 阅读 · 0 评论 -
数组应用小结(一)
数组是类型相同的对象的序列,其中的对象称为数组元素。数组是C/C++中最常用的数据结构,由于数组名类似于指针,加上C/C++不会对数组边界进行检查,所以在数组运用过程中很容易出错。下面总结下自己对数组的理解:1. 数组名是一个"常量地址"(函数名也是),不能作为左值。(按道理是不能对数组名再“取地址”的,编译系统做了“容错”处理,就是把“取常数地址的地址”与“常数地址”等价成一回事原创 2014-10-15 19:35:12 · 1661 阅读 · 0 评论 -
自测题1道
看到这样一样题,想想就简单的写了写,还是有很多收获。需求:1.模拟银行,客户关系封装类;2.客户到银行办理业务需先排队;3.银行根据队列处理业务,优选选择金卡客户;4.办理建卡、存款、取钱、销户业务。代码思路:1.定义银行类,客户类,队列类;2.思考现实实例,银行、队列只能有一个实例,客户可以有多个实例3.理清类关系,银行依赖于队列决定客户,银行依赖客户数据处理原创 2014-08-13 12:13:06 · 784 阅读 · 0 评论 -
new的理解
在编码过程中,我们常用new来分配堆内存.MyClass *p = new Myclass;在这个过程中,实际上经历了3个步骤:1.调用operator new 分配堆内存; void *p = operator new(sizeof(MyClass))2.调用MyClass的构造函数 MyClass::MyClass();3.调用placement new 返回类原创 2014-08-22 14:00:53 · 1327 阅读 · 0 评论 -
多重继承
多重继承(MI),说简单点就是一个派生类继承了多个基类。在面向对象程序设计时,我们需要MI,比如:在一个家庭中,孩子同时继承了父亲和母亲的一些特性;如果用单继承该怎么弄?我们每天使用的类iostream就是多重继承出来的,MI在iostream中的作用是代码重用。MI在日常编码中用的很少,主要原因是: 1. 一些“特性”被加入标准C++(尤其是模板)后,改变了我们的对原创 2015-09-08 16:59:51 · 969 阅读 · 0 评论 -
理解RTTI
在我编码过程中,基本上没有用过RTTI,我想主要原因是:1.破坏了多态;2.RTTI会产生额外开销。 关于RTTI的概念,网络上很多,对于我来说,曾经有一个理解误区:在使用dynamic_cast(source_pointer)时,将基类的指针转化为派生类的指针,就是基类会凭空长出一截成为派生类,这种理解是错误的。要想使用dynamic_cast(source_pointer)将原创 2015-07-15 16:55:10 · 856 阅读 · 0 评论 -
编译时常量enum
在看C++元编程时, 发现基本上都举的这么一个例子:#include using namespace std;template struct Factorial { enum T{ value = N * Factorial::value };};template <>struct Factorial { enum { value = 1 };};i原创 2015-06-12 15:50:14 · 1327 阅读 · 0 评论 -
浅析cout
cout是iostream类的一个对象,它有一个成员运算符函数operator我一直有一个疑问: 为什么函数operator我在下例中作了简单的测试,1.利用printf实现了简单的myOutstream.2.在自定义类(myData)中使用友元函数friend const myOutstream& operator 使用myOutstream对象myCout能够输出私有原创 2015-06-24 14:20:44 · 1013 阅读 · 0 评论