C++
文章平均质量分 62
C++基本知识和高级知识
一只老风铃
欣于所遇,暂得于己,快然自足。
展开
-
字符串对象的简易实现
字符串对象String类型是字符串对象类型,其内部的实现方式主要有三种:vector方式的动态内存法指针法(即通过char*指向对应字符串区域)短字符串优化法(当字符串较短时,存在自身的char[]数组中,超过一定长度采取指针来指向)三种方法的不同,主要是存放方式,以及拷贝复制时不同,指针法可能采取浅拷贝(指向同一片区域),vector法采取深拷贝(指向不同副本),短字符串优化(更为复杂)指针法实现class m_string{private: char* ptr;原创 2021-09-02 14:39:24 · 177 阅读 · 0 评论 -
智能指针的简易实现
实现智能指针智能指针为了解决C/C++中动态内存的泄漏问题,这通常是由于程序忘记释放动态内存或者程序提前结束导致动态内存无法释放。RAIIRAII (Resource Acquire Is Initlaziation) 资源获取即初始化:其利用C++中对象的特性,即当一个对象脱离其作用域后,对象将自动调用析构函数完成释放。那么将资源的申请和释放对应于对象的构造和析构函数中,即可完成对资源的智能化管理。引用计数对于动态内存的管理,若该内存为多个对象所使用的动态内存,那么通常采取引用计数原创 2021-09-02 14:29:31 · 676 阅读 · 0 评论 -
再谈std:string
string的三种实现方式《Effctive STL》中提及std:string有三大类实现方式方法原理无特殊处理 eager copy采取类似于std:vector的数据结构,早期实现方式Copy On Wirte 写时复制即维护一个指向字符串存储空间的指针短字符串优化SSOstring对象本身空间可以存放16长度以内字符串,长字符串则由指针指向常见C++实现库采取的string实现方法:库实现方式g++ std:stringCO原创 2021-03-19 11:27:59 · 494 阅读 · 0 评论 -
GDB调试①:断点设置与分步执行
gdb是符合gpl自由公共许可证的gun体系下调试工具,功能简洁易用,可以随心所欲的查看程序运行过程中的信息。一个app程序:#include<iostream>using namespace std;int func(int a,int b){ return a+b;}int main(){ int* arr=new int[3]; arr[0]=1; arr[1]=2; arr[2]=func(arr[0],arr[1]);原创 2020-11-07 02:46:41 · 6439 阅读 · 0 评论 -
C++11 资源移动std:move
C++11引入右值引用的目的:避免频繁的临时对象的拷贝,复制带来的低效率:实参=》形参 函数返回值等都需要进行拷贝这些左值的频繁拷贝带来不可忽视的性能开销,特别是参数为结构体、对象类型时。而右值引用的提出解决了临时对象的频繁销毁和拷贝过程,其基本的思想是:利用即将结束生命周期的右值的资源,从而避免临时对象的销毁和拷贝而C++中提供将左值转化为右值引用的转化: std::move() ...原创 2020-11-02 00:09:44 · 712 阅读 · 0 评论 -
C++ 内存泄漏与valgrind排查
内存泄漏指程序运行过程中,不再被使用的运行时堆内存没有被及时的释放,造成可用空间不断减少内存泄漏的主要原因有:程序在通过malloc new等申请动态内存时,未对应执行free delete 程序包含free delete 但调用过程中发生异常(跳转到其他区域)异常处理在没有进行释放 程序提前return 遗漏掉free delete的执行linux>top #查看系统当前进程运行情况 包括内存占用可以看到其中排在第一个的内存占用是: 11.2% Linux下..原创 2020-10-30 13:27:20 · 323 阅读 · 0 评论 -
C++11:Lambda匿名函数
C++11新增的匿名函数 Lambda表达式,其格式如下:[capture捕获列表](参数列表)->返回类型{函数体}其中capture捕获列表用于获取其所在scope的上下文变量。关于捕获capture:通过[=] :Lambda表达式所在块scope的上下文变量以传值方式全部捕获。int a=3;int main(){ int a=1; int b=2; auto fun=[=](){return a+b;}; //捕获所在sco原创 2020-10-04 23:57:52 · 456 阅读 · 0 评论 -
C++11:语法糖-自动类型推导auto与decltype
C++11引入自动类型推导,首先在源代码中自动类型相当于占位符,编译器在编译阶段根据上下文关系推导出实际的类型,并根据实际的类型进行编译。auto:根据auto定义时,实际的右边类型进行编译。大大简化编程工作,并且由于编译期确定,不会带来运行期负担。int main(){ map<string,int> mp; mp["str1"]=1; mp["str2"]=3;//传统遍历map方式 需要书写冗长的类型 for(map<string原创 2020-10-04 21:56:34 · 452 阅读 · 0 评论 -
RAII思想:资源管理就是对象管理
RAII技术 Resource Acuqsiton IS Initialzation是基于C++语言特性的一种资源管理思想,被认为是一种简洁、高效、安全的方式。资源是对一类信息,数据的抽象,在程序中包括套接字资源,锁资源,内存资源。对资源的处理方式为:申请资源 使用资源 释放资源我们发现,在资源的获取和释放途中,程序很可能出现问题。以数据库资源为例:lockDB();.....操作数据库.....unlockDB();若操作数据库途中发生异常或提前return控制转移出.原创 2020-10-03 03:38:57 · 297 阅读 · 0 评论 -
关于异常:类型最先匹配与异常对象拷贝
异常处理是这样一类机制,它允许我们在程序执行过程中遇到异常情况时处理这类突发事件,C++中使用throw关键字来抛出异常事件,被抛出的异常通过类型来区分,抛出的位置称为抛出点,其会被写入到异常变量中,而外层通过catch(类型)来捕获异常并处理。其基本使用方式是通过try{ .....throw() ...} catch( ){} 方式来在异常情况出现时,抛出异常和处理异常。#include<iostream>using namespace std;class mal...原创 2020-10-03 02:37:54 · 319 阅读 · 0 评论 -
过程调用与运行时栈
过程是程序的一种抽象,以一组参数和返回值实现对一个功能的封装,过程包含的形式有:函数、方法、处理函数等过程调用必须解决的三大机器级别问题:控制转移:过程P调用过程Q,进入过程Q时,程序计数器设置为Q的代码起始地址,在Q执行完成返回时,需要把程序计数器设置为P调用Q位置的下一条指令地址。参数传递:P必须为Q提供若干个参数,Q可以向Q返回一个值内存分配与释放:被调用过程Q可能会为局部变量分配空间,而在返回前,又需要释放这些局部空间。【运行时栈】栈数据结构为后进先出,这与函数调..原创 2020-10-01 11:57:30 · 505 阅读 · 0 评论 -
C++11:关于右值引用
首先,程序中有左值和右值的概念:左值:located value 可定位值,其含义是可以明确其存放地址的值,更确切说对其的使用是基于地址右值:read value 可读的值,通常指代赋值运算=右侧的常量值,字面值,或者函数的返回值,它们没有具体的指代名,即无法通过地址访问,通常在赋值表达式结束后变销毁。一般可以认为:左值对应变量的地址,右值对应变量的值int value=fun();对于该赋值表达式,表达式左边的value为左值,可以被赋值,而fun()的返回值是临时存放的右值,语句结原创 2020-10-01 01:40:54 · 423 阅读 · 1 评论 -
实现自己的静态链接库与动态链接库
静态链接库是指在源代码中调用库中的函数,再被编译为.o目标文件后,再链接上库文件,形成可执行程序。库文件中存放多个.o目标文件,它们存放着各个函数的定义,最终被一起链接进可执行程序。那么在运行期之前,可执行程序中就包含所有程序运行的条件,也就是所谓的静态链接。首先,新建两个.cpp文件 add.cpp sub.cpp 它们中都定义了两个简单的函数g++ -c add.cpp sub.cpp生成如下2个对象文件 add.o sub.o进一步,通过nm命令查看该.o文件...原创 2020-09-30 00:10:57 · 310 阅读 · 2 评论 -
编译期初始化与运行期初始化
编译期初始化:在源代码被编译过程中,编译期安插一些代码逻辑,完成确定的内存分配(并非实际分配内存,而是确定其大小占用,由编译期安插代码),变量的初始化。如:全局变量为内置类型,并且大小确定int a=2; static int b=3; //static的不同只是其只在本文件中可见static int c=a+b;在编译期初始化,那么在实际运行期都是确定的结构和逻辑,将带来更高的性能,因为编译器完成了一定的工作。加载时初始化:在main()函数执行前,完成包括全局变量,..原创 2020-09-28 22:53:59 · 1947 阅读 · 1 评论 -
pthread 多线程
多线程程序指的是在同一个程序中多个执行流并发执行,它们共享进程的同一个地址空间,分别完成相应的任务,并通过共享地址空间等方式完成线程间通信,CPU按照时间片轮转等方式对线程进行切换和调度。通常而言,线程共享的进程资源包括:线程之间共享内存地址空间中的堆区,也就是动态创建的区域 同时每个线程有自己的堆栈区,以进行函数调用和返回,局部变量的创建与销毁。 在进行线程切换时,每个线程依据相应的寄存器组保护现场和还原现场 线程共享进程打开的文件描述符(FD : linux中认为一切IO设备可采取文件描述原创 2020-09-27 19:00:06 · 890 阅读 · 0 评论 -
关于static关键字与extern关键字
static关键字主要应用在三方面:第一:修饰一般变量或函数,此时该变量或函数将只能在本文件中被访问,而一般的变量(不加static)则成为全局变量#include <iostream>using namespace std;class A{public: A() { cout<<"A() constructor"<<endl; } ~A() { cout<<"~A原创 2020-09-27 01:28:05 · 218 阅读 · 0 评论 -
关于IEEE浮点数表示
计算机表示整数是精确的,这得益于任何一个整数都可以转换为若干个2的幂次方相加关于整数其主要包含两大类:无符号整数:以unsigned int 32位无符号整型为例:其表示的值是所有相应二进制位中为1的位对应2的幂次方相加因此表示范围为 0 =》2的32次方-1(32位中全为1) 不能表示负数有符号整数:以int 32位整型为例:第一位为符号位:表示 (若为1) 0(若为0) 记为k131位同无...原创 2020-09-25 11:49:50 · 1242 阅读 · 0 评论 -
linux g++ 编译流程
g++是GNU实现的编译器(包含预编译器 编译器 汇编器 链接器)预编译阶段:主要是文本操作 文本包含 文本替换(宏)文本剪切(条件编译)处理三大类预编译指令:条件编译 宏定义 文件包含hello.cpp #define MAX 1000int main(){ std::cout<<MAX<<endl; }执行预编译指令: g++ -E hello.cpp可以看到,并没有报错:即预编译阶段只进行文本处理,如宏M...原创 2020-09-25 00:53:26 · 1242 阅读 · 0 评论 -
boost/smart_ptr 智能指针
Java相对于C++,采取垃圾回收机制避免程序设计人员手动的进行动态内存的释放,其原理是采取引用计数和可达性分析判断对象是否被引用,并及时的回收这些不可达的对象。而C++ Boost库提供智能指针,也是采取类似的思想,将指向动态申请的内存空间的指针交由智能指针对象管理。智能指针对象通过引用计数等方法完成对所对应指针指向内存的管理。智能指针对象被存放在栈中,因此随着入栈出栈,智能指针对象的析构过程调用也伴随着其所指内存的释放。测试类:class test{private: i原创 2020-09-25 00:26:40 · 173 阅读 · 0 评论 -
static_cast与dynamic_cast静态类型转换与运行期类型转换
类型转换是C/C++中重要的一种转换,对于内置类型的转换,其往往伴随着精度丢失或者转换失败。而对于继承体系中的类类型转换,可分为两大类别:向上转换:将派生类的指针引用转换为基类的指针或引用,根据里式替换规则,这类转换是安全的。 向下转换:将基类的指针引用转换为派生类的指针或引用,由于不确定基类指针实际指向,所以这类转换是不安全的。C++实现多态的核心是虚函数,其一种通俗的描述是:通过基类指针引用指向不同的子类,而采取统一地调用方法,虚函数机制能够确保根据实际的指向对象不同调用相应的函数。.原创 2020-09-21 18:10:27 · 616 阅读 · 0 评论 -
多线程安全的单例:C++实现
单例模式要求只能产生一个该类的实例,因此采取的方法是禁用构造函数,拷贝构造函数,=重载操作符。禁用函数一般可以采取将函数放置于private acess section,同时提供static对外提供实例访问接口,在多种线程安全单例的实现方法中,还需要考虑多线程中的安全性:饿汉式:类一初始化时就完成instance的创建:...原创 2020-09-19 11:06:39 · 682 阅读 · 0 评论 -
关于编译器自动生成Default Constructor的4种必要情况
关于默认构造函数,有两点误区:对于任何一个没有定义构造函数的类,都会被合成一个默认构造函数 编译器合成的默认构造函数会设定Class中每一个data member的初始值编译器什么时候需要为Class生成一个默认的构造函数? : 需要的时候为了编译器需要,一些必要的构造函数被生成,它们之中有一些情况下是十分必要的,那么nontrivial(有价值的) default constructor被合成,主要包含4种情况:①带有Default Constructor 的 Membe...原创 2020-09-17 01:07:44 · 380 阅读 · 0 评论 -
预编译与编译
一C/C++源代码从最初的文本变为可执行文件主要进行三大步预编译阶段:主要是编译器执行代码文本处理工作,并不会进行语法检查主要执行三大类预编译命令宏定义:代码文本替换功能,将使用了宏的地方采取宏定义方式直接展开条件编译:代码文本剪切功能,根据设定的条件选择性删除一些代码片段包含文件: 代码文本插入功能 #include 包含其他头文件,#include其内部实现是将被包含的头文件代码插入到当前代码文本中编译阶段:将预编译阶段产生的带编译源码进行语法检查,编译成目标文件(.o类型.原创 2020-09-16 23:52:32 · 1617 阅读 · 0 评论 -
C++ 对象内存模型
继承,封装,多态是面向对象的三大特性之一,以类为例,类分为数据成员和函数而函数分为static、非static、virtual函数三大类函数,那么一般的C++对象其内存模型是如何。类中存在部分:成员变量 静态成员变量 成员函数 静态成员函数 构造函数 析构函数 虚函数 虚析构函数 纯虚函数通常而言对于一个对象,其在内存中的模型不包含函数,只包含成员,而函数单独存放,所有对象通过地址进行调用。对象在内存模型及其占用大小受几方面因素影响:成员变量虚表指针虚基类表指.原创 2020-09-12 15:40:22 · 1522 阅读 · 0 评论 -
strcpy memcpy strlen的实现
strcpy将一个const char* src指向的字符内存空间 复制到dst内存空间中,直到遇到'\0'结束符 同时'\0'结束符也被复制过去char* my_strcpy(char* dst, const char* src) //将src指向的字符串复制到dst中 直到遇到'\0'结束符{ if (dst == 0 || src == 0) return nullptr; char* res = dst; //最终返回首地址 while (*sr原创 2020-09-10 15:35:27 · 268 阅读 · 0 评论 -
C++ 虚表指针Vptr与虚函数表Vtable
面向对象语言的三大特性:继承、封装、多态其中多态的含义是同一方法的具体执行与实际调用者上下文环境密切有关。绑定是函数调用者与具体函数入口的关联,即如何定位到函数的执行地址静态绑定:也称为编译期绑定,在程序没有运行前,就可将函数调用与具体执行代码关联 动态绑定:在实际运行期,判断引用对象的实际调用的方法静态多态与动态多态静态多态:主要通过重载与模板实现,其在编译期就可以确定实际的调用地址 动态多态:主要依靠虚函数来实现,不同的编译器其虚函数实现原理不同虚函数的基本使用方法:.原创 2020-09-04 21:16:23 · 933 阅读 · 0 评论 -
Leetcode 链表加法模拟
题目描述假设链表中每一个节点的值都在 0 - 9之间,那么链表整体就可以代表一个整数。给定两个这种链表,请生成代表两个整数相加值的结果链表。例如:链表 1为 9->3->7,链表 2为 6->3,最后生成新的结果链表为 1->0->0->0。示例1输入复制[9,3,7],[6,3]输出复制{1,0,0,0}思路:由于链表末尾才表示数的最低位,因此传统遍历方式不行,采取递归的思路,核心实现:等长链表的...原创 2020-08-27 11:43:14 · 533 阅读 · 0 评论 -
Leetcode LRU_Cache缓存结构设计
题目描述设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能set(key, value):将记录(key, value)插入该结构 get(key):返回key对应的value值[要求]set和get方法的时间复杂度为O(1) 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。思路:get需要O(1)复杂度 那么底层需要采取map实现同时set需要..原创 2020-08-27 10:58:04 · 490 阅读 · 0 评论 -
C++ 限制类的创建在堆中或栈中
C++中对象的创建,体现在字面上包含两种A a 该方式为静态创建,即在栈空间挪出一定空间,然后调用相应的构造函数完成创建和初始化。 A* a=new A()该方式为动态创建,在堆空间中首先operator new()申请内存,并调用构造函数完成初始化。只能在栈中创建那么也就是不能通过new方式动态申请堆中空间,采取禁用operator new()方式,具体实现为修改为private不可访问class A{private: void* op...原创 2020-08-19 12:03:25 · 491 阅读 · 1 评论