
C++的学习
文章平均质量分 77
讲述C++,总结学习C++
林林林ZEYU
坚持
展开
-
917-gcc和g++是什么,有什么区别?
gcc 和 g++是什么,有什么区别?目前(2020-09)GCC 编译器已经更新至 10.2版本,其功能也由最初仅能编译 C 语言,扩增至可以编译多种编程语言,其中就包括 C++ 。除此之外,当下的 GCC 编译器还支持编译 Go、Objective-C,Objective-C ++,Fortran,Ada,D 和 BRIG(HSAIL)等程序,甚至于 GCC 6 以及之前的版本还支持编译 Java 程序。但本教程主要讲解如何使用 GCC 编译器编译运行 C 和 C++ 程序,因此有关其它编程语言如何原创 2021-12-18 11:55:12 · 564 阅读 · 0 评论 -
877-C++如何实现一个不被继承的类?
C++如何实现一个不被继承的类?(一)单例模式下的不被继承的类从继承的特性来说,派生类继承其基类的私有成员,但是不可访问;派生类的构造要先调基类的构造函数构造基类然后在调自己的构造函数构造自己;我们可以将基类的构造函数写在private下,那么基类此时就是一个不被继承的类;但是这样基类是不可被继承,但同时他也不会正常实例化对象,因为不可访问其私有成员;这时我们可以借助单例模式来实现,通过静态方法实现返回一个对象,但是这种实例化的方式不符合我们正常类的实例化;所以此方法不是最优解,我们期望实现一个类可原创 2021-11-27 13:43:44 · 437 阅读 · 0 评论 -
836-C++STL容器内容总结
C++ STL容器分类通过下面表格,罗列一下常用到的C++STL容器(包含C++11新引入的容器):顺序容器这部分对于顺序容器进行一下内容总结。vector容器内容梳理底层数据结构:内存可以2倍扩容的数组,默认构造的vec对象底层没有分配空间,随着增加元素才从0-1-2-4-8-16-32…这样的方式进行扩容,所以vec容器初始的内存使用效率比较低,可以使用reserve方法进行优化。数据增删查接口:reserve/resize成员方法:reserve是给vector容器预留空间,并不原创 2021-11-19 00:15:02 · 294 阅读 · 0 评论 -
821-对C++11多线程join()和detach()的理解
每一个程序至少拥有一个线程,那就是执行main()函数的主线程,而多线程则是出现两个或两个以上的线程并行运行,即主线程和子线程在同一时间段同时运行。而在这个过程中会出现几种情况:1、主线程先运行结束2、子线程先运行结束3、主子线程同时结束在一些情况下需要在子线程结束后主线程才能结束,而一些情况则不需要等待,但需注意一点,并不是主线程结束了其他子线程就立即停止,其他子线程会进入后台运行join()join()函数是一个等待线程完成函数,主线程需要等待子线程运行结束了才可以结束detach()函原创 2021-11-17 17:12:44 · 262 阅读 · 0 评论 -
811-C++11多线程-线程局部存储(thread_local)
引言线程局部存储在其它语言中都是以库的形式提供的(库函数或类)。但在C++11中以关键字的形式,做为一种存储类型出现,由此可见C++11对线程局部存储的重视。C++11中有如下几种存储类型:C++11多线程-线程局部存储(thread_local)thread_local 是 C++ 11 新引入的一种存储类型,它会影响变量的存储周期。C++ 中有 4 种存储周期:automaticstaticdynamicthread有且只有 thread_local 关键字修饰的变量具有线程(th原创 2021-11-15 19:41:39 · 1193 阅读 · 0 评论 -
810-C++11使用using定义别名(替代typedef)
C++11使用using定义别名(替代typedef)大家都知道,在 C++ 中可以通过 typedef 重定义一个类型:typedef unsigned int uint_t;被重定义的类型并不是一个新的类型,仅仅只是原有的类型取了一个新的名字。因此,下面这样将不是合法的函数重载:void func(unsigned int);void func(uint_t);//error: redefinition使用 typedef 重定义类型是很方便的,但它也有一些限制,比如,无法重定义一个模板原创 2021-11-15 13:20:20 · 187 阅读 · 0 评论 -
808-C++ this指针
C++ this指针首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员函数如何知道哪个对象的数据成员要被操作呢,原因在于每个对象都拥有一个指针:this指针,通过this指针来访问自己的地址。注意:this指针并不是对象的一部分,this指针所占的内存大小是不会反应在sizeof操作符上的。this指针的类型取决于使用this指针的成员函数类型以及对象类型。this指针的概念1、定义在 C++ 中,每一个对象都能通过 t原创 2021-11-14 20:55:54 · 172 阅读 · 0 评论 -
807-C++多继承下,派生类对象有几张虚函数表?
C++多继承下,派生类对象有几张虚函数表?我们看下面这个示例:#include <iostream>#include <string>#include <typeinfo>using namespace std;class Base1//基类{public: Base1() : x(1) {} virtual void play() { cout << "Base1::play basketball" << endl; }原创 2021-11-14 13:10:49 · 2453 阅读 · 3 评论 -
806-如何通过编译器选项查看 C++ 类内存布局
使用 CL 编译器选项查看 C++ 类内存布局今天,在这里和大家分享一下, VS系列编译器 CL 的一个编译选项可以查看 C++ 类的内存布局,非常有用。使用如下:打开VS2019编译器:选择 VS 的命令行工具,按如下格式使用:>cl –d1reportSingleClassLayout[classname] test.cpp而使用 –d1reportAllClassLayout 则可以查看源文件中所有类及结构体的内存布局。其中,classname 为类名,我们可以自由选择想要查原创 2021-11-14 12:39:55 · 694 阅读 · 0 评论 -
804-C++11 decltype类型推导
C++ decltype类型推导decltype 是 C++11 新增的一个关键字,它和 auto 的功能一样,都用来在编译时期进行自动类型推导。decltype 是“declare type”的缩写,译为“声明类型”。既然已经有了 auto 关键字,为什么还需要 decltype 关键字呢?因为 auto 并不适用于所有的自动类型推导场景,在某些特殊情况下 auto 用起来非常不方便,甚至压根无法使用,所以 decltype 关键字也被引入到 C++11 中。auto 和 decltype 关键原创 2021-11-13 19:24:02 · 154 阅读 · 0 评论 -
803-C++11 auto类型推导
C++11 auto类型推导在 C++11 之前的版本(C++98 和 C++ 03)中,定义变量或者声明变量之前都必须指明它的类型,比如 int、char 等;但是在一些比较灵活的语言中,比如 C#、JavaScript、PHP、Python 等,程序员在定义变量时可以不指明具体的类型,而是让编译器(或者解释器)自己去推导,这就让代码的编写更加方便。C++11 为了顺应这种趋势也开始支持自动类型推导了!C++11 使用 auto 关键字来支持自动类型推导。auto 类型推导的语法和规则在之前的 C转载 2021-11-13 13:48:44 · 239 阅读 · 0 评论 -
802-C++标准异常的基类exception
C++ exception类:C++标准异常的基类C++语言本身或者标准库抛出的异常都是 exception 的子类,称为标准异常(Standard Exception)。你可以通过下面的语句来捕获所有的标准异常:try{ //可能抛出异常的语句}catch(exception &e){ //处理异常的语句}之所以使用引用,是为了提高效率。如果不使用引用,就要经历一次对象拷贝(要调用拷贝构造函数)的过程。exception 类位于 < exception &g原创 2021-11-12 17:58:56 · 404 阅读 · 0 评论 -
800-C++ throw(抛出异常)详解
C++ throw(抛出异常)详解抛出(Throw)--> 检测(Try) --> 捕获(Catch)异常必须显式地抛出,才能被检测和捕获到;如果没有显式的抛出,即使有异常也检测不到。在 C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为:throw exceptionData;exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool 等基本类型,也可以是指针、数组、原创 2021-11-12 13:59:21 · 8026 阅读 · 0 评论 -
799-C++异常类型以及多级catch匹配
C++异常类型以及多级catch匹配首先来回顾一下上篇博客讲到的 try-catch 的用法:try{ //可能抛出异常的语句}catch(exceptionType variable){ //处理异常的语句}我们还遗留下一个问题,就是 catch 关键字后边的exceptionType variable,这节就来详细分析一下。exceptionType是异常类型,它指明了当前的 catch 可以处理什么类型的异常;variable是一个变量,用来接收异常信息。当程序抛出异常原创 2021-11-12 13:15:52 · 235 阅读 · 0 评论 -
798-C++异常处理(try catch)
C++异常处理(try catch)程序运行时常会碰到一些错误,例如除数为 0、年龄为负数、数组下标越界等,这些错误如果不能发现并加以处理,很可能会导致程序崩溃。C++ 异常处理机制就可以让我们捕获并处理这些错误,然后我们可以让程序沿着一条不会出错的路径继续执行,或者不得不结束程序,但在结束前可以做一些必要的工作,例如将内存中的数据写入文件、关闭打开的文件、释放分配的内存等。程序的错误分类大致可以分为三种,分别是语法错误、逻辑错误和运行时错误:1、语法错误在编译和链接阶段就能发现,只有 100%原创 2021-11-12 11:52:41 · 3557 阅读 · 0 评论 -
797-模拟实现C++智能指针shared_ptr和weak_ptr
模拟实现C++智能指针shared_ptr#include<iostream>#include<new>#include<stdio.h>#include<atomic> using namespace std;class Object{private: int value;public: Object(int x = 0) :value(x) { cout << "construct object" << en原创 2021-11-11 21:11:59 · 851 阅读 · 0 评论 -
787-C++的RAII机制
C++中的RAII机制什么是RAII?RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。为什么要使用RAII?上面说到RAII是用来管理资源、避免资源泄漏的方法。那么,用了原创 2021-11-09 10:47:18 · 151 阅读 · 0 评论 -
775-C++设计模式 - 代理模式
C++设计模式 - 代理模式代理模式(结构型模式)代理Proxy模式 : 通过代理类,来控制实际对象的访问权限举个例子:客户 助理Proxy 老板(委托类)代理类和委托类是组合!!!#include <iostream>#include <memory>using namespace std;/*代理模式(结构型模式) 代理Proxy模式 : 通过代理类,来控制实际对象的访问权限客户 助理Proxy 老板(委托类)代理类和委原创 2021-11-07 21:19:51 · 170 阅读 · 0 评论 -
774-C++设计模式 - 装饰器模式
C++设计模式 - 装饰器模式装饰器模式 Decorator(结构型模式—类和对象的组合,组合方式)该设计模式的目的是:负责功能扩展通过子类实现功能增强的问题:为了增强现有类的功能,通过实现子类的方式,重写接口,是可以完成功能扩展的,但是代码中有太多的子类添加进来了!!!所以我们通过装饰器模式看看效果如何!!!#include <iostream>#include <memory>using namespace std;/*装饰器模式 Decorator(结构型原创 2021-11-07 21:17:38 · 176 阅读 · 0 评论 -
773-C++设计模式 - 适配器模式
C++设计模式 - 适配器模式适配器模式:让不兼容的接口可以在一起工作举个例子电脑 =》 投影到 =》 投影仪上接口的类型有:VGA HDMI TypeC假如我们有VGA接口的电脑, 刚好(TV)投影仪也是VGA接口:class VGA//VGA接口类{public: virtual void play() = 0;};//TV01表示支持VGA接口的投影仪class TV01 : public VGA{public: void play() { co原创 2021-11-07 21:14:35 · 199 阅读 · 0 评论 -
772-C++设计模式 - 观察者Observer模式
观察者模式简介观察者模式又叫做观察者(Observer)监听者(Listener)模式,也叫发布(Publish)订阅(Subscribe)模式,常用于解耦事件的观察和事件最终的处理方式,举个例子说明:例子:基于同一组数据,生成了很多不同的界面来显示,有曲线图显示方式,有圆饼图显示方式,有柱状图显示方式等等…,当底层数据发生改变时,所有基于同一组数据的图像显示都需要修改图像,那么此时有两种实现方式:1、所有图形界面模块都去观察底层数据是否做了改变,如果变化,那么读取数据,修改图像显示2、此时有一个类原创 2021-11-07 20:19:11 · 470 阅读 · 0 评论 -
771-C++设计模式 - 迭代器模式
迭代器模式简介先介绍一下迭代器模式的含义,迭代器模式Iterator的核心功能,就是提供了一种特定的方法,顺序访问一个容器中的各个元素,既不会暴露容器的内部设计细节(容器底层数据结构),又可以让外部代码透明的访问集合内部的所有元素。先给出迭代器模式的一个UML类图设计如下:所以一个迭代器最基本应该提供下面这几个接口操作,代码如下:#include<iostream>using namespace std;//迭代器的抽象基类template<typename _Ty&g原创 2021-11-07 18:05:13 · 275 阅读 · 0 评论 -
765-如何避免vector动态扩容?为什么是2倍或者1.5倍扩容?
如何避免vector动态扩容?vector的扩容机制:当向vector插入元素时,如果元素的有效个数和空间容量相等时,vector内部会自动触发扩容机制,而扩容主要分3步骤:开辟新空间,拷贝元素,释放旧空间。但是每次扩容时,新空间的开辟不能太大,也不能太小,太大容易造成空间的浪费,太小了则会导致扩容频繁而影响程序的运行效率。那既然扩容会影响程序的运行效率,那我们如何来避免呢?在插入元素之前,我们可以预估vector里面要存储多少个元素,我们提前将这个空间给它开辟好就可以了!!!比如说,我们需要向v原创 2021-11-05 14:05:36 · 2047 阅读 · 1 评论 -
752-C++设计模式 - 简单工厂,工厂方法和抽象工厂
设计模式概念设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,与我们自己摸索出来的问题解决之道相比较,有以下优点可取:1.代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够2.做到软件设计要求的“开-闭原则”,即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活3.合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的根本原则“高内聚,低耦合”Simple Fac原创 2021-11-03 14:11:43 · 219 阅读 · 0 评论 -
751-C++设计模式—单例模式
设计模式概念设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,与我们自己摸索出来的问题解决之道相比较,有以下优点可取:1、代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好2、当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够做到软件设计要求的“开-闭原则”,即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活3、合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的根本原则“高内聚,低耦合”单例模式简介单例模原创 2021-11-02 22:20:09 · 371 阅读 · 0 评论 -
737-C++STL - 容器空间配置器allocator的原理
实现一个简单的vector容器C++ STL所有容器的实现都需要依赖一个空间配置器allocator,虽然我们平时使用容器的时候并没有注意,但是我们却一直在使用它,C++ STL库提供了一个默认的空间配置器allocator的实现,比较简单,当然我们需要深入了解空间配置器的原理,然后就可以提供自定义的allocator了。先看一个简单的vector容器的实现,代码如下:#include <iostream>using namespace std;/*这篇文章主要讲述空间配置器,所以实原创 2021-10-30 21:50:39 · 369 阅读 · 0 评论 -
732-C++实现线程安全的链式栈
C++实现线程安全的链式栈#include <iostream>#include<mutex>#include<thread>using namespace std;struct empty_stack : std::exception//异常类的封装{ const char* what() const throw();};template<class T>class Stack{private: struct StackNode/原创 2021-10-29 20:23:02 · 2815 阅读 · 0 评论 -
727-C++11 - thread多线程编程,线程互斥和同步通信,死锁问题分析解决
C++11的多线程类threadC++11之前,C++库中没有提供和线程相关的类或者接口,因此在编写多线程程序时,Windows上需要调用CreateThread创建线程,Linux下需要调用clone或者pthread线程库的接口函数pthread_create来创建线程。但是这样是直接调用了系统相关的API函数,编写的代码,无法做到跨平台编译运行。C++11之后提供了thread线程类,可以很方便的编写多线程程序(注意:编译器需要支持C++11之后的语法,推荐VS2019,g++4.6版本以上),代原创 2021-10-28 22:09:38 · 881 阅读 · 0 评论 -
724-C++迭代器iterator详解
迭代器概念迭代器有什么用处?泛型算法的参数为什么接收的都是迭代器?迭代器iterator是C++ STL的组件之一,作用是用来遍历容器,而且是通用的遍历容器元素的方式,无论容器是基于什么数据结构实现的,尽管不同的数据结构,遍历元素的方式不一样,但是用迭代器遍历不同容器的代码是完全一样的。经典的迭代器遍历容器的代码如下:vector<int>::iterator it = vec.begin();for (; it != vec.end(); ++it){ cout <<原创 2021-10-27 22:15:34 · 2143 阅读 · 0 评论 -
722-深入掌握C++智能指针
智能指针介绍学习C++的人,一直在接触裸指针,一边感受着它的强大,一边感受着它的坑爹。当然,坑不坑爹在于我们开发者,指针本身近乎完美,但奈何用的人不理解,给自己埋下无数的坑,还哭喊着指针不好用,那么今天要介绍的智能指针可以释放大家在使用裸指针时的一些压力,当然智能指针无法替代裸指针的全部功能。裸指针到底有什么不好,写过一些C++代码的人应该都能知道,比如下面的原因:1.忘记释放资源,导致资源泄露(常发生内存泄漏问题)2.同一资源释放多次,导致释放野指针,程序崩溃3.明明代码的后面写了释放资源的代码原创 2021-10-26 22:52:25 · 302 阅读 · 0 评论 -
717-C++继承与多态
继承的好处是什么?1.基类给所有派生类提供公共的属性(成员变量)和方法(成员函数),通过继承达到代码复用的目的。2.基类可以给所有派生类提供统一的纯虚函数接口,派生类通过函数重写,达到多态调用的目的。(OOP的很多设计模式离不开继承和多态,为了达到良好的软件设计,如高内聚,低耦合,遵循‘开-闭’原则等,继承和多态是必须涉及到的)。OOP面向对象语言如C++,Java,Python,PHP等,非常重要的一项语言特征就是继承,继承首先可以做到代码的复用,派生类通过继承基类,可以复用基类的成员变量和成员方法原创 2021-10-25 14:41:10 · 243 阅读 · 0 评论 -
716-详解C++的右值引用
C++左值引用与右值引用我们先来看看左值引用:int main(){ int a = 0; int &b = a; b = 20; return 0;}反汇编代码: int a = 10; // 这条mov指令把10放到a的内存中0112436E mov dword ptr [a],0Ah int &b = a; /* 下面的lea指令把a的地址放入eax寄存器 mov指令把eax的内容放入b内存里面*/01124375 lea原创 2021-10-25 00:19:29 · 355 阅读 · 0 评论 -
713-C++11容器emplace方法原理剖析
C++11容器emplace方法的现象C++11容器的push和insert方法,都匹配了emplace的新的方法,也是用来添加数据的。emplace使用的时候感觉和之前的功能是一样的,都是添加新的元素,但是到底有什么不同呢?示例代码1#include<iostream>#include<vector>using namespace std;class Test{public: Test(int a) { cout << "Test(int)"<原创 2021-10-24 09:46:38 · 2434 阅读 · 0 评论 -
712-C++智能指针shared_ptr的易错点
问题代码1#include<memory>#include <iostream>using namespace std;class A{public: A() :mptr(new int) { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; delete mptr; mptr = nullptr; }private: int*原创 2021-10-23 21:16:04 · 596 阅读 · 0 评论 -
706-建议用make_shared代替shared_ptr
建议用make_shared代替shared_ptr我们看看shared_ptr我们先看下面的代码:对于sp1来说,它的内存布局如下:指向资源的指针指向资源引用计数的指针对于源码上的成员变量:我们看看shared_ptr的源码上资源引用计数对象的成员:强智能指针的计数和弱智能指针的计数。转换成图解如下:只有uses从1减到0,智能指针shared_ptr才能析构释放其所指向的资源。这样子,确实是存在缺陷!!!这句代码,存在2个内存开辟:1、堆内存的资源 ,也就是我们想托原创 2021-10-18 12:12:06 · 626 阅读 · 0 评论 -
699-实现STL的function迷你版
实现STL的function迷你版char buffer[1024] = { 0 };template<typename Functor, typename R, typename... A>struct Invoker{ static R invoke(A... args) { Functor* p = (Functor*)buffer; return (*p)(args...); }};template<typename Fty>class myf原创 2021-10-18 00:02:00 · 203 阅读 · 0 评论 -
657-C/C++总结(一)
1、程序的内存布局程序运行时叫进程就是进程的虚拟地址空间这张图是32位x86体系下的进程的虚拟地址空间,下面是低地址,上面是高地址我们从最下面(低地址开始看)往上看,从0-0x08048000是0地址,然后从0x08048000往上,放的是代码段(.text段:指令,只读不能写),数据存储的.Data和.BSS段,然后是堆Heap(malloc,new),然后是共享库(printf,scanf这类要包含头文件的函数,比如说,我们写printf或者scanf,要包含<stdio.h>,这原创 2021-09-29 12:38:18 · 459 阅读 · 0 评论 -
628-C++复习总结
1、地址传递和引用传递区别?C++中引用和指针的概念和区别?先通过swap例子引出引用和指针,然后在Windows上通过VS2019,打断点,跳转到汇编指令。或者在linux上gcc -g,通过gdb调试转到汇编指令。转到用指针实现的swap和用引用实现的swap函数的汇编指令上看,引用和指针在底层的汇编指令是一样的。拿32位系统来说,定义一个指针,底层开辟4个字节,然后把它指向的变量的内存地址放到这4个字节里面,当我们去查看汇编指令的时候,定义一个引用的时候也是在栈上开辟4字节的内存,把它所引用的变原创 2021-09-22 18:15:04 · 287 阅读 · 0 评论 -
550-海量数据查重和求topK问题
海量数据的综合应用查重:数据是否有重复,以及数据重复的次数topK:有几亿个数字。求元素的值,前K大/小,第K大/小去重:去掉重复多次的数字,数字只保留一份。海量数据的查重问题1.哈希表(得看有没有对内存的限制,如果没有限制,就是直接用哈希表解决)比如说 50亿(5G)个整数的查重问题, 10亿个整数内存大约是1G,50亿个整数相当于内存是5G,一个整数4个字节,如果要算50亿个整数的查重问题的话,如果要用一个哈希表把这50亿个数据全部存储下来,就得花20G的内存,链式哈希表每个节点还得有一个地原创 2021-09-12 20:01:40 · 609 阅读 · 0 评论 -
547-C++11的原子类型
我们在前面的博客里实现的窗口卖票的代码,使用的是下面这种线程安全的操作:int count=100;lock_guard<std::mutex> guard(mtx);count++;lock_guard<std::mutex> guard(mtx);count--;但是互斥锁是比较重的,如果临界区代码做的事情稍稍复杂,比较多,我们用这个互斥锁是应该的。但是像简单的对变量的++或者–,就不需要用互斥锁了。我们应该用CAS来保证上面++ --操作的原子特性就足够了原创 2021-09-11 21:07:09 · 153 阅读 · 0 评论