
C++基础知识
文章平均质量分 65
C++基础知识
TABE_
这个作者很懒,什么都没留下…
展开
-
C++中可变参数宏
可变参数宏(Macro With Variable Number of Arguments or Variadic Macro) 是指我们可以像定义能够接受不同数量参数的普通C++函数一样,定义一个能够接受不同数量参数宏。原创 2023-04-27 19:56:01 · 1511 阅读 · 1 评论 -
C++ STL的空间配置器
一级配置器的实现思想实际就是对c下的malloc,relloc,free进行了封装,并且在其中加入了c++的异常。我们要了解对于当内存不足调用失败后,内存不足处理是用户需要解决的问题,STL不处理,只是在你没有内存不足处理方法或有但是调用失败后抛出异常。二级配置器是通过内存池和空闲链表配合起来的一个特别精巧的思想。空闲链表的每个节点分别维护以8的倍数的各内存大小(8,16,32…128字节)。首先,用户申请内存小于128个字节,进入二级配置器程序,...原创 2022-08-25 16:29:13 · 821 阅读 · 0 评论 -
C++ new
这里写目录标题newoperator newplacement newnewnew operator就是new操作符,不能被重载,假如A是一个类,那么A * a=new A;实际上执行如下3个过程:调用operator new分配内存,operator new (sizeof(A))调用构造函数生成类对象,A::A()返回相应指针事实上,分配内存这一操作就是由operator new(size_t)来完成的,如果类A重载了operator new,那么将调用A::operator new(s原创 2022-03-02 19:47:14 · 288 阅读 · 0 评论 -
C++ malloc/free/new/delete详解(内存管理)
这里写目录标题malloc/free典型用法内存分配实现过程new/delete典型用法内存分配实现过程new/delete和malloc/free的区别malloc/free典型用法malloc()负责动态配置内存,大小由size决定,返回值成功时为任意类型指针,失败时为NULL。void * malloc(size_t size)free()负责释放动态申请的内存空间,调用free( )后ptr所指向的内存空间被收回,如果ptr指向未知地方或者指向的空间已被收回,则会发生不可预知的错误,如果原创 2021-12-27 20:21:33 · 10467 阅读 · 4 评论 -
C++内存分配的几种策略
内存分配的几种策略静态的栈式的堆式的区别静态的静态的存储区:内存在程序编译的时候就已经分配好,这块的内存在程序整个运行期间都一直存在。它主要存放静态数据、全局的static数据和一些常量。栈式的在执行函数(方法)时,函数一些内部变量的存储都可以放在栈上面创建,函数执行结束的时候这些存储单元就会自动被释放掉。栈内存包括分配的运算速度很快,因为内置在处理器的里面的。当然容量有限。堆式的也叫做动态内存分配。有时候可以用malloc或者new来申请分配一个内存。在C/C++可能需要自己负责释放(java原创 2022-05-01 20:29:03 · 1956 阅读 · 0 评论 -
堆和栈的区别
堆和栈主要有以下几点不同:1. 申请方式栈:由系统自动分配。例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间。堆:需要程序员自己申请,并指明大小。例如,C中的malloc函数p1 = (char *)malloc(10)。C++中的new运算符p2 = new char[10]。但是p1、p2本身是在栈中的。2. 申请后系统的响应栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内原创 2022-04-07 19:53:24 · 13772 阅读 · 0 评论 -
C++内存模型
一个由C++编译的程序占用的内存分为以下六个部分:堆heap:由malloc分配的内存块,其释放编译器不去管,由我们程序自己控制(一个new对应一个delete)。如果程序员没有释放掉,在程序结束时OS会自动回收。涉及的问题:“缓冲区溢出”,“内存泄露”。栈stack:是那些编译器在需要时分配,在不需要时自动清除的存储区。存放局部变量、函数参数。存放在栈中的数据只在当前函数及下一层函数中有效,一旦函数返回了,这些数据也就自动释放了。全局/静态存储区(.bss段和.data段):全局和静态变量被分配到原创 2021-12-23 22:12:15 · 794 阅读 · 0 评论 -
C++内存对齐
这里写目录标题空类/静态成员内置类型数据成员结构体数据成员虚函数继承内存对齐的意义内存对齐的基本原则:结构(struct/class)的内置类型数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的起始位置要从自身大小的整数倍开始存储。如果一个结构A里有结构体成员B,则结构体A的成员要从结构体B内部“最宽基本类型成员”的整数倍地址开始存储(如struct a里存有struct b,b里有char, int, double等元素,那b应该从8的整数倍位置开始存储)。结构体的总大小为结原创 2021-12-29 21:03:54 · 4147 阅读 · 2 评论 -
C/C++中基本数据类型所占内存大小
C++中不同数据类型所占的字节大小,在不同的操作系统和编译器下,是不同的,一般主要说gcc下,32位或64位系统的,做了个表如下:注意:1.求数组大小时,如果数组作为参数传递时,退化为指针,所以sizeof(arr)大小为该系统下指针的大小。2. 对于C字符串,需要牢记C/C++中一个汉字占两个字节(Linux下3个字节)。3.求struct 或者 class 的大小时候,除了nonstatic data members 的大小,特别要考虑的是字节对齐问题,如果是C++的还涉及虚函数的虚表问题,需原创 2021-05-08 16:48:38 · 1211 阅读 · 0 评论 -
static在自定义类中的使用
这里写目录标题static数据成员声明与初始化使用static成员函数声明定义调用注意事项static数据成员声明与初始化static数据成员的声明在类的内部,而初始化在类的外部,且初始化 不需要static关键字。使用static数据成员的使用有两种方法:类名::静态数据成员对象. 静态数据成员static成员函数声明static成员函数的声明在类内部。定义static成员函数的定义可以在类内部或者外部,但是在外部定义时,不用加static关键字。调用调用静态成员函数时,静原创 2022-03-08 20:25:09 · 1375 阅读 · 0 评论 -
const在自定义类中使用时的注意事项
这里写目录标题const在自定义类中的使用const数据成员声明和初始化const成员函数声明定义调用const对象static在自定义类中的使用static数据成员声明与初始化使用static成员函数声明定义调用const在自定义类中的使用const数据成员声明和初始化const 常数据成员在使用前必须被初始化。也就是声明的同时就要初始化,之后不能再去赋值,只能使用。可以在类中初始化const数据成员(不推荐),或初始化参数列表中初始化const数据成员(推荐)。const成员函数声明co原创 2021-12-27 18:47:25 · 506 阅读 · 0 评论 -
C++ 纯虚函数
这里写目录标题定义为何引入纯虚函数抽象类定义纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加 =0:virtual void funtion1()=0为何引入纯虚函数引入纯虚函数的理由有如下两个:为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。将函数定义为纯虚函数,则编原创 2021-12-28 19:46:38 · 553 阅读 · 0 评论 -
C++ 虚函数详解(动态绑定)
这里写目录标题概述类的虚表一般继承(无虚函数覆盖)一般继承(有虚函数覆盖)多重继承(无虚函数覆盖)多重继承(有虚函数覆盖)虚表指针动态绑定概述C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。类的虚表每个包含了虚函数的类都包含一个虚表。我们来看以下的代码。类 A 包含虚函数vfunc1,vfunc2,由于类 A 包含虚函数,故类 A 拥有一个虚表。class A {public: virtua原创 2021-12-27 21:18:32 · 13145 阅读 · 1 评论 -
C++ 虚拟继承
这里写目录标题为什么需要虚继承虚拟继承中的内存分布情况sizeof问题为什么需要虚继承虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继 承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如 下:class Aclass B1:public virtual A;class B2:public virtual A;class D:public B1原创 2022-03-01 21:02:25 · 5456 阅读 · 0 评论 -
C++ 多重继承详解
C++ 多重继承多重继承的语法多重继承下的构造函数多重继承下的命名冲突派生类对象中数据成员的排列形式多重继承的语法多重继承的语法也很简单,将多个基类用逗号隔开即可。例如已声明了类A、类B和类C,那么可以这样来声明派生类D:class D: public A, private B, protected C{ //类D新增加的成员}D 是多继承形式的派生类,它以公有的方式继承 A 类,以私有的方式继承 B 类,以保护的方式继承 C 类。D 根据不同的继承方式获取 A、B、C 中的成员,确定它原创 2022-02-21 19:55:47 · 2842 阅读 · 0 评论 -
C++ 继承详解
C++ 继承继承语法继承方式改变访问权限名字遮蔽继承时的对象模型无变量遮蔽有变量遮蔽继承语法继承的一般语法为:class 派生类名:[继承方式] 基类名{ 派生类新增加的成员};继承方式继承方式包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private。不同的继承方式会影响基类成员在派生类中的访问权限。(1)public继承方式基类中所有 public 成员在派生类中为 public 属性;基类中原创 2022-02-21 20:21:41 · 16318 阅读 · 5 评论 -
C++类成员的访问权限
C++通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。所谓访问权限,就是你能不能使用该类中的成员。在类的内部(定义类的代码内部),无论成员被声明为 public、protected 还是 private,都是可以互相访问的,没有访问权限的限制。在类的外部(定义类的代码之外),只能通过对象访问成员,并且通过对象只能访问 public 属性的成员,不能访问 private、protected 属原创 2022-02-21 20:34:50 · 960 阅读 · 0 评论 -
C++空类中有哪些默认的函数
这里写目录标题C++的空类会有6个默认的函数。即默认构造函数、默认拷贝构造函数、默认析构函数、默认赋值运算符,这四个是我们通常知道的。但是除了这四个,还有两个,那就是取址运算符和const 取址运算符,即总共有六个函数。一个示例如下:class Empty{public: Empty(); // 缺省构造函数 Empty( const Empty& ); // 拷贝构造函数 ~Empty(); // 析构函数 Empty& operator=( const Empty&原创 2022-05-18 20:20:57 · 3100 阅读 · 0 评论 -
构造函数和析构函数能抛出异常吗?
但是当无法保证析构函数中不发生异常时,该怎么办呢?析构函数不能、也不应该抛出异常。构造函数可以抛出异常,但是不建议这么做。原创 2022-08-16 20:29:33 · 2040 阅读 · 0 评论 -
C++ 构造函数和析构函数是否可以为虚函数?
简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。理由如下:构造函数不能是虚函数1.从vptr角度解释虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还没有初始化!2.从多态角度解释虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型来调用函数,例如通过原创 2021-05-14 15:28:14 · 7565 阅读 · 2 评论 -
C++ =default
在c++中如果我们自行定义了一个构造函数,那么编译器就不会再次生成默认构造函数,我们先看如下的代码我们定义一个类,这个类没有定义构造函数,此时在下面一段代码依然可以正常使用,我们加上一个自定义构造函数:此时编译器会报错,原因很简单,我们自定义了一个构造函数,以前的默认构造函数没了,我们要用如下的方式调用:如果我们还要使用无参构造函数得在定义时自己写个好了此时不报错了,但是这样写代码执行效率没有编译器生成的自定义函数的效率高,为了解决这个问题,C++11 标准引入了一个新特性:default 函数。程原创 2022-08-30 21:35:23 · 5692 阅读 · 0 评论 -
C++中的五种构造函数
C++中的构造函数可以分为4类:默认构造函数、普通构造函数、拷贝构造函数、转换构造函数。(1)默认构造函数。未提供显式初始值时,用来穿件对象的构造函数。以Student类为例,默认构造函数的原型为Student();//没有参数Student(int num=0;int age=0);//所有参数均有默认值(2)普通构造函数C++用于构建类的新对象时需要调用的函数Student(int num,int age);//有参数(3)复制(拷贝)构造函数复制构造函数在以下三种情况下会被调用。原创 2021-05-12 17:10:32 · 22800 阅读 · 3 评论 -
C++构造函数和析构函数的调用顺序
构造函数的调用顺序1.virtual base class的构造函数被调用。2.nonvirtual base class的构造函数被调用。3.本类对象的vptr被初始化,指向 本类的虚表vtbl。4.成员类的构造函数,如果有member initialization list的话,将在本类的构造函数的体内拓展开来,这必须在vptr被设定之后才做,以免有一个virtual member function被调用。5.本类的构造函数及其内部的代码被执行。析构函数的调用顺序1.本类的析构函数及其内部原创 2021-05-13 15:49:47 · 340 阅读 · 0 评论 -
C++ 成员初始化列表
这里写目录标题数据成员是对象数据成员的类型是const或者引用子类初始化父类的私有成员使用成员初始化列表的优点在以下三种情况下需要使用初始化成员列表:需要初始化的数据成员是对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);需要初始化const修饰的类成员或初始化引用成员数据;子类初始化父类的私有成员;数据成员是对象如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,原创 2021-12-29 21:24:52 · 3089 阅读 · 1 评论 -
C++11移动构造函数详解
这里写目录标题拷贝构造函数修改后的拷贝构造函数移动构造函数移动构造函数的优点当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。拷贝构造函数C++在三种情况下会调用拷贝构造函数(可能有纰漏),第一种情况是函数形实结合时,第二种情况是函数返回时,函数栈区的对象会复制一份到函数的返回去,第三种情况是用一个对象初始化另一个对象时也会调用拷贝构造函数。除了这三种情原创 2021-12-29 19:39:43 · 8436 阅读 · 12 评论 -
C++ 左值和右值
左值和右值左值、右值左值引用、右值引用std::move()std::move()的实现引用折叠左值、右值在C++11中所有的值必属于左值、右值两者之一,右值又可以细分为纯右值、将亡值。在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。举个例子,int a = b+c, a 就是左值,其有变量名为a,通过&a可以获取该变量的地址;表达式b+c、函数int func()的返回值是右值,在其被赋值给某一变量前,我们不能通过变量名找到它,&(b+c原创 2022-01-20 21:21:31 · 7678 阅读 · 1 评论 -
匿名函数 lambda函数
lambda语法所谓lambda是一份功能定义式,可被定义于语句(statement)或表达式(expression)内部。因此你可以拿lambda当作inline函数使用。最小型的lambda函数没有参数,什么也不做,如下:[]{ std::cout<< "hello lambda" <<std::endl;}可以直接调用它:[]{ std::cout<<"hello lambda" <<std::endl;}(); //prints "原创 2021-04-01 23:46:12 · 227 阅读 · 0 评论 -
C++ 指针容器 boost::ptr_vector
boost::ptr_vector是由boost实现的指针容器。如果我们光放对象指针到vector里面,容器析构的时候虽然会析构自己开辟出来的存放指针的空间,但不会析构指针本身指向的空间,于是有了boost::ptr_vector这个指针容器,boost::ptr_vector的特点如下:boost::ptr_vector 专门用于动态分配的对象,它使用起来更容易也更高效。boost::ptr_vector 独占它所包含的对象,因而容器之外的共享指针不能共享所有权,这std::vector<bo原创 2022-03-22 20:49:23 · 2326 阅读 · 0 评论 -
C++ 智能指针
C++STL共提供了四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中C++11只支持后三个,C++98支持所有四个。STL智能指针auto_ptrunique_ptrshared_ptrweak_ptrshare_ptr和weak_ptr的核心实现Counter简单实现share_ptr的简单实现weak_ptr简单实现auto_ptrauto_ptr采用所有权模式,下面有一个例子:auto_ptr<string> p1 (new原创 2021-05-29 22:31:48 · 8153 阅读 · 4 评论 -
C++ RAII(Resource Acquisition is Initialization)
RAII应用场景1 智能指针2 锁操作3 其他在RAII的指导下,我们应该使用类来管理资源,将资源和类对象的生命周期绑定,在构造函数中申请分配资源,在析构函数中释放资源,由于stack winding会保证抛出异常时自动调用未析构类的析构函数,实现资源和状态的安全管理。将初始化和资源释放都移动到一个包装类中的好处:保证了资源的正常释放。省去了在异常处理中冗长而重复甚至有些还不一定执行到的清理逻辑,进而确保了代码的异常安全。简化代码体积。1 智能指针智能指针(std::shared_ptr和原创 2021-05-29 21:33:28 · 365 阅读 · 0 评论 -
C++ pthread库
pthread库基本函数创建线程终止线程连接线程分离线程互斥量mutex条件变量cond其余函数线程属性线程属性结构体线程属性函数基本函数创建线程int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);参数说明:第一个参数表示线程id。第二个参数表示线程参数。第三个是线程的入口函数,入口函数的返回值必须为void*,且入口函数必须为原创 2021-07-22 18:29:32 · 4815 阅读 · 0 评论 -
为什么条件变量的wait函数需要传入一锁作为参数
要注意到,#1和#2两步已经不是原子操作了,那么就有可能有如此情景:在当前线程(A)执行完#1行代码后到执行#2代码前的时间间隔里,另一线程(B),获取到了锁,修改了条件使其满足,然后发送了信号condA。而此时线程A还未被加入到condA的等待队列中,造成线程A错过了通知一直阻塞,直至下一次通知,如果没有下一次通知,那么A将永远等待下去,比如B也需要A的相关条件变量通知才能再次发出condA的通知。此为,为保证“解锁”和“加入等待队列”两操作的原子性,条件变量的wait函数需要传入一锁作为参数。.....原创 2022-08-16 21:01:28 · 653 阅读 · 0 评论 -
C++11多线程相关类
C++11 新标准中引入了五个头文件来支持多线程编程,他们分别是 ,,,和。mutexcondition_variable创建ThreadA和ThreadB两个线程,线程分别运行的是A和B两个函数,线程ThreadB通过cv.wait()来阻塞等待,线程ThreadA通过修改全局标志位和cv.notify_one()来唤醒ThreadB继续往下运行。...原创 2022-06-18 15:53:15 · 206 阅读 · 1 评论 -
C++11 auto和decltype
∶。原创 2022-08-28 20:44:29 · 714 阅读 · 0 评论 -
C++11 新特性
这里写目录标题“语法糖”auto自动类型推导lambda表达式右值引用与移动语义右值引用移动语义完美转发 Perfect Forwarding智能指针C++11多线程编程目前用到过的C++11新特性主要分为以下四个方面:“语法糖”: auto自动类型推导,初始化列表, lambda表达式等。右值引用和移动语义智能指针C++11多线程编程:thread库“语法糖”auto自动类型推导C语言也有auto关键字,但是其含义只是与static变量做一个区分,一个变量不指定的话默认就是auto。因原创 2022-03-09 20:32:42 · 2914 阅读 · 0 评论 -
前置++和后置++的区别
前置++的返回类型是Age&,后置++的返回类型const Age。这意味着,前置++返回的是左值,后置++返回的是右值。前置++与后置++的操作符重载函数,函数原型必须不同,否则就违反了重载函数必须拥有不同的函数原型的语法规定。前置++的效率更高,理由是:后置++会生成临时对象,会造成一次构造函数和一次析构函数的额外开销。该类重载了前置++和后置++两个操作符,以实现对年龄的自增。前置++没有形参,而后置++有一个int形参,这是为了绕过语法的限制。左值和右值,决定了前置++和后置++的用法。原创 2022-09-05 21:48:47 · 1067 阅读 · 0 评论 -
C++ sizeof
length()是因为沿用C语言的习惯而保留下来的,string类最初只有length(),引入STL之后,为了兼容又加入了size(),它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。string类的size()/length()方法返回的是字节数,不管是否有汉字。可以看到,sizeof(a)是20个字节,sizeof(b)是4个字节,也就是说sizeof(b)只是求出了指针b的大小。,参数可以是数组、指针、类型、对象、函数等。(1)size()用于取对象大小。......原创 2022-08-17 20:22:16 · 464 阅读 · 0 评论 -
C++容器类插入和删除元素时迭代器的失效情况
容器底层数据结构类型 具体容器 内存分配特点 insert操作后迭代器失效情况 erase操作后迭代器失效情况 数组型数据结构 vector,string,deque,array 元素分配在连续的内存中 如果插入后重新分配空间,则所有迭代器都会失效;如果插入后未重新分配空间,会使得插入点之后的元素向后移动,故插入点之后的迭代器全部失效 会使得删除点之后的元素向前移动,故删除点及其之后的迭代器全部失效 链表型数据结构 list,forwar...原创 2022-01-19 20:31:38 · 670 阅读 · 0 评论 -
char *s1 和 char s2[] 的区别
【代码】char *s1 和 char s2[] 的区别。原创 2022-08-23 10:49:07 · 590 阅读 · 0 评论 -
C++ string、int和char的相互转换
首先,需要强调的是:0-9对应的ASCLL码值为48-57其次,从string中访问得到的string[index]为char类型,用单引号’c’表示1.char转int用char减去’0’即可得到char对应的int值,char减去整数0得到其ASCII值。int main() { char c = '1'; cout << c - 0 << endl;//49 cout << c - '0' << endl;//1}原创 2021-05-10 17:22:02 · 907 阅读 · 0 评论