C++
文章平均质量分 74
C++ 语法专栏。主要就是对C++ Primer的总结
我什么都布吉岛
Keep writing,Keep thinking!
展开
-
关于C/C++的换行
可以分为两种情况:下面可以但是最好不要这么做的用法(可读性):宏函数倒是挺常见的:二、长字符串换行两种方式实现长字符串在编辑区换行。将一个大字符串拆分成属于不同行的、引号字符串。这种情况下,每一行右侧引号左侧的缩进无需考虑,因为它不属于这个长字符串。因为字符串是一个整体,所以必须要用反斜杠。在C++11以后,支持了一种所见即所得的一种方式。[1] https://stackoverflow.com/questions/1135841/c-multiline-string-literal...原创 2022-06-27 10:33:27 · 26462 阅读 · 0 评论 -
extern关键字
extern关键字主要用于改变全局变量的默认链接行为。对于一个const全局变量,默认链接行为是内部的,也就是const只在本文件是可见的;对于一个普通全局变量,默认是外部的,要特别注意重复定义问题。......原创 2022-01-25 20:00:00 · 1927 阅读 · 0 评论 -
对比一下指针和引用
BASIS FOR COMPARISONPOINTERREFERENCE定义指针是存着内存地址的变量引用是变量的别名变量地址操作符*, ->&空引用可指向空永远不为空初始化创建不一定初始化创建一定要初始化初始化时期程序运行的任何时间点只能在创建之时初始化赋值根据需要可以多次赋值任何时候都不能再次赋值从CPU角度看引用和指针,其实两者并没有什么区别。也就是说引用是底层实现还是指针;从top-level、low-...原创 2021-11-12 10:17:35 · 326 阅读 · 0 评论 -
标准库(三)正则表达式
一、正则表达式是什么?正则表达式是一种描述字符串的一种手段。正则表达式像是一系列字符串特征的描述,比如我们需要在一系列文本中找出xxx@foxmail.com的字符串,我们就可以通过描述正则表达式这个特征找出所有的email地址。正则表达式在很多地方都有应用,如文本合法性表达,网络爬虫,文本替换等等。二、正则表达式库简介C++11已经支持正则表达式(RE库),头文件在regex2.1 正则组件组件名含义regex表示一个正则表达式类regex_match将一个字符串与原创 2021-11-09 10:02:16 · 1129 阅读 · 0 评论 -
标准库(二)输入输出类文件流2
编程中难免会遇到处理文件,C++定义了fstream和ofstream处理文件设备。一、文件流的特有操作操作含义fstream fstrm创建一个未绑定的文件流fstream fstrm(s)创建一个名为s的文件流fstream fstrm(s,mode)以模式mode创建一个文件名为s的文件fstrm.open(s)打开名为s的文件并与fstrm绑定(无返回值)fstrm.close()关闭与fstrm的绑定(无返回值)fstrm.is_op原创 2021-11-05 10:14:31 · 230 阅读 · 0 评论 -
标准库(二)输入输出类概述1
C++作为一种面向对象的语言,处理输入和输出都是通过一系列定义在标准库的类来完成的。IO库可以读写内置类型,用户也可以通过定义自己的IO操作,读取自己专属的IO操作。C++处理IO的主要思想是“流”,数据和水流一样,写入和读出。一、IO类有那些?最常见的流是关联到控制台的,用户的所有操作(键盘输入、屏幕显示)都是在这样的流中完成的,没错他就是标准输入输出(iostream),另外一个常见的流就是文件流(fstream),输入输出操作都是关联到文件的,最后一个就是字符串流(sstream),这样的流一般用原创 2021-11-04 13:45:42 · 204 阅读 · 0 评论 -
异常处理简介
一个程序的功能是有限的,那些超出函数正常功能范围的行为称为异常,最常见的异常包括数据库连接断开、遇到意外输入。异常实际是系统中最难设计的一部分。一、throw表达式程序异常检测部分使用throw表达式引发一个异常。throw后的表达式类型就是异常类型,来看一个最简单的类型:void printAge(int age){ if(age<0) throw std::runtime_error("Age < 0"); std::cout<<"age"<<原创 2021-08-15 18:25:00 · 3022 阅读 · 0 评论 -
原子操作实现无锁同步
原子操作是我们常常听到的一个概念,合理使用原子操作可以显著降低因为锁同步耗费时间。文章首先将会解决以下问题:为什么需要互斥锁互斥锁的成本如何用原子操作替代互斥锁为什么需要互斥锁?主要为了解决多个线程并发造成的数据争抢导致的脏数据。下面的程序创建了十个线程,线程执行的内容都是将全局变量count自加1一万次,按照正常逻辑,最终的count结果应该是:10W。#include <iostream>#include <vector>#include <algori原创 2021-08-12 10:21:36 · 758 阅读 · 0 评论 -
函数指针声明及其简化
不使用关键字简化auto关键字(最简单)decltype关键字tail指定auto推断类型typedef别名using别名(可识别性高)#include <iostream>#include <vector>#include <memory>using namespace std;typedef int(*Pfun)(double, double);using Pfunfun = int(*)(double, double);int fu.原创 2021-07-21 23:15:18 · 260 阅读 · 0 评论 -
auto和decltype区别和联系
随便说说auto相对于decltype而言多了一个初始化操作,有时候我们并不希望推断完成后就给他赋予和用来推断的对象的初值。auto i=33;auto以右侧操作数33为推断依据,给出对象i的两方面信息:类型为int初始值为33auto对于大多数情况来说特别有用,如范围forstd::vector<double> dvec{1,2,3,4,5,6,7};for(auto r:dvec) std::cout<<r<<" ";其优势在泛型编程时特别明原创 2021-07-21 22:33:32 · 339 阅读 · 0 评论 -
简单理解大端小端
数是按字节存储的十进制数4660是如何在计算机内存中存储的?我们知道计算机存储的单元是字节,4460转换成十六进制,一共有四字节,因为char arr[] = { 0x12,0x34 };std::cout << "Big Endian will be:";std::cout << ((0x34 << 8) + 0x12) << std::endl;std::cout << "Little Endian will be:";std::c原创 2021-07-14 11:18:22 · 3464 阅读 · 0 评论 -
标准库(一)时间和日期工具
在很多地方我们都需要用到时间这个维度的描述,C++标准库把时间概念抽象成一个库std::chrono,这个库包括三个方面内容:clocktime pointduration一、时钟类型 clockclock是标准库用于描述时间来源的类。时间来源可以来源于系统,也可以来源于gps、文件等,比较常见的三种来源是:system_clocksteady_clockhigh_resolution_clock他们都是静态对象,可以直接使用其方法。如std::chrono::system_clo原创 2021-05-15 09:09:34 · 430 阅读 · 0 评论 -
数组与函数参数
一、数组和std::vector区别内置数组是在连续空间中,存放同类对象的的一种数据结构,与std::vector的区别在于其灵活性,前者大小固定灵活性差,但是效率略高,后者大小动态调整,有对应的方法。相同之处在于:都存放着同类对象每个成员都是无名的可以通过下标访问因为数组本身是对象,因此可以定义数组的引用、数组的指针,该如何正确理解复杂的数组类型?int *ptrs[10];//存放着10个int *的数组int &ref[10]=/* ?*/;//不存在,因为10个int &原创 2021-06-24 17:14:29 · 242 阅读 · 0 评论 -
allocator 解决了new的局限性
一、new的局限性new的局限性体现在其将对象构造和内存分配组合在一起,对象析构和内存回收组合在一起,这会导致资源的浪费,最重要的是不是所有的对象都有构造函数。string * const p=new string[n];//n个空stringstring s;string * q = p;while(cin>>s&&q!=p+n) *q++=s;const size_t size=q-p;delete [] p;这个例子读取了用户的输入字符串,用户输入的字符原创 2021-06-19 11:14:30 · 391 阅读 · 0 评论 -
常见容器序列构造操作
整数序列 iota#include <numeric>std::list<int> l(10);std::iota(l.begin(), l.end(), -4);其中-4为起点,填充的个数为10个。序列作有规律变换 transformtemplate< class InputIt, class OutputIt, class UnaryOperation >OutputIt transform( InputIt first1, InputIt last1原创 2021-05-22 11:10:56 · 255 阅读 · 0 评论 -
作用域、存储时期和链接
以下都是基于C语言的描述。一、作用域作用域是衡量标识符作用范围的一个或多个区域。主要分为三种:代码块作用域函数原型作用域文件作用域函数作用域(goto语句)代码块作用域一般指的是函数体,如:void fun(int i){ //这里代码块作用域}函数原型作用域,指的是出现在函数参数部分的变量:void use_a_VLA(int n,int m,int ar[n][m])这里的n、m在中括号的使用就是函数原型作用域。文件作用域文件作用域是作用范围是工程下所有源文件,如原创 2021-04-15 00:13:29 · 133 阅读 · 0 评论 -
预处理功能调试 assert和NDEBUG
头文件#include <cassert>assert是一种预处理宏(preprocessor macro),使用一个表达式作为其条件。assert(expr);首先对expr进行求值,如果表达式为假,输出信息并终止程序;如果表达式为真,什么也不发生。默认情况下,assert启用,你可以通过以下两种情况使其失效:编译时通过-D传递NDEBUG宏源文件#define 定义NDEBUG宏总的来说,assert应该用在确实不可能发生的情况,仅用于调试,不用于代替运行时逻辑检查。当然N原创 2021-02-25 21:53:58 · 430 阅读 · 0 评论 -
迭代器和指针的区别
迭代器封装了“遍历容器”的方法。不同容器的遍历实现有差异,如数组只需要给定偏移即可遍历,可链表则需要一些“复杂”的跳转操作,由此可见,迭代器通过封装统一了遍历操作,降低了编程的复杂度(迭代器帮你做了)。举个简单的例子,自定义找最大值的函数功能findMax,对于不同容器你必须得定义一个数组版和链表版的重载函数,继续定义不同容器,你不仅需要费神去思考该结构遍历操作细节,重载的形式更是多种多样。迭代器将各种容器的操作进行了抽象,隐去了操作细节,用户只需要根据抽象出来的操作完成任务。具体的,他们之间的区别是:原创 2021-02-23 20:08:11 · 1251 阅读 · 0 评论 -
迭代器实现二分搜索
#include <iostream>#include <vector>using namespace std;bool isFound(vector<double> dvec, double value){ auto b = dvec.begin(), e = dvec.end(); auto m = (e - b) / 2 + b; //1 2 3 4 (第三个,中间靠右) // 1 2 3 4 5(第三个,正中间) while (m != e原创 2021-02-20 14:17:22 · 171 阅读 · 0 评论 -
运算符优先级
表达式表达式是由运算符和操作数构成的。操作数:常量、变量和两者组合运算符:C语言大约有40种运算符,有优先级每一个表达式都有一个值!运算符的优先级为表达式的求值顺序提供了重要规则,但是它并不决定所有的顺序y=6*12+5*20;表达式的求值以运算符优先级作为参考,有的运算符与另一运算符共享操作数,那么此时的优先级就会正确指导我们表达式求值。“+”与左右两边的“”共享12和5常量,优先级“”大于“+”,所以表达式会先执行“”,有一点需要注意,就是612和5*20都是的求值顺序不确定,哪个先计算原创 2021-02-20 13:54:09 · 2467 阅读 · 0 评论 -
迭代器与算法
C++算法库定义了一系列函数,用于查找、排序、技术和操纵某个范围(range),这个范围是按照左闭右开的方式给出的,也就是容器迭代器中的[first,last)。一、分类STL算法中使用迭代器作为输入和输出,具体到不同算法对迭代器的要求也有所区别,有些算法(find)只要求迭代器访问元素、递增迭代器和比较迭代器的能力;而有些算法(sort)则要求读写、随机访问能力。我们知道不是所有容器都具有“理想”迭代器的所有功能,如我们的forward_list就不具备“后撤”、随机访问能力,如果迭代器加上const原创 2021-02-08 00:18:27 · 1060 阅读 · 0 评论 -
容器额外的迭代器
一、什么是迭代器?迭代器设计思维是STL的关键所在。迭代器(iterators)是一种抽象的设计概念,现实程序语言中没有直接对应这个概念的实物,在《Design Patterns》对迭代器的定义如下:提供一种方法,使之能够依序巡防某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达形式。STL的中心思想在于,将数据容器(containers)和算法(algorithms)分开,彼此独立设计,最后再以贴胶着剂将他们撮合起来[1]。本文讨论的重点不在于迭代器的实现,而在于如何使用,如何利用迭代器加原创 2021-01-31 22:16:52 · 201 阅读 · 0 评论 -
仿函数及可调用对象类型
回调函数是一种模式,普通函数指针、仿函数和lambda则是实现这个模式的一种手段。一半而言,lambda函数比仿函数更加简洁,仿函数则需要更多的代码量,普通函数指针也可以作为回调的手段,不过效率相对要低一些罢了。回调函数Wikipedia:计算机编程中,回调函数是:可执行代码作为参数传入其他可执行代码并由其他的可执行代码执行这段可执行代码可以分为同步和异步回调两种。仿函数仿函数其实就是一个重载了调用运算符的类,这个类的特点是看上去函数(这也是为什么他叫“仿函数”)。// 这是一个仿函.原创 2021-01-27 23:20:02 · 425 阅读 · 0 评论 -
我对命名空间的理解
命名空间(namespace)表示一个标识符(identifier)的可见范围。在C++中具体表现为一系列变量、函数及类的集合,优点在于:减少命名冲突;(主要原因)模块化。将逻辑相关的标识符组织起来,系统更加整洁、清楚;为什么命名空间能够减少命名冲突?不同开发者有不同的开发习惯、命名规则,当协同开发时就难免会遇到命名冲突的问题,为了解决这个问题,C++使用命名空间这一概念封装了所有对象名称。如小明和小红namespace xiaoming{ int a = 2; double pi = 3原创 2020-11-25 00:03:14 · 279 阅读 · 0 评论 -
空字符和空白字符
空格、制表符、换行符(创建新行)、回车符、换页符、垂直制表符称为“空白字符”,因为它们与打印页上的单词和行之间的空格一样都是起到方便阅读的作用。 标记由空白字符和其他标记分隔(划分边界),如运算符和标点。 在分析代码时,C 编译器将忽略空白字符,除非您将它们用作分隔符或者字符常量或字符串文本的组成部分。 使用空白字符可以让程序更易于阅读。 请注意,编译器也将注释视为空白。C语言的空字符是在字符串结尾系统自动加上的\0,以让系统识别出一个字符内串的结尾。如:字符串“china”。在系统内是以“china\0原创 2020-11-20 09:45:21 · 9725 阅读 · 0 评论 -
值初始化和默认初始化
一个对象要么执行默认初始化,要么执行值初始化。如果对象有初值,那么执行值初始化;若没有初值则执行默认初始化。根据默认初始化的类型和位置,有两种情况:内置类型。局部作用域,不初始化;全局、静态变量初始化为0。自定义类、[1] C++定义了一套包括算术类型(Arithmetic type)和空类型(void)在内的基本数据类型,也叫做基本内置类型。算术类型它包括:bool char wchar_t char16_t char32_t short int long long long float dou原创 2020-11-03 14:41:07 · 563 阅读 · 0 评论 -
using关键字小结
目前为止,using至少可以在以下几种场景应用:释放命名空间的变量、函数、类和模板使用命名空间指定的变量、函数、类和模板类型别名对于前两个应用,主要原因是取名字很麻烦。不同开发者有不同的开发习惯、命名规则,当协同开发时就难免会遇到命名冲突的问题,为了解决这个问题,C++使用命名空间这一概念封装了所有对象名称。如小李和小红namespace Li{ //variables, functions, classes,templates;}namespace Hong{ //v原创 2020-10-24 11:32:22 · 246 阅读 · 0 评论 -
pair是键值对
一、pair是键值对标准库中的关联容器map含有多个键值对,该键值对就是使用pair实现的,其头文件#include <utilty>。二、pair简单介绍2.1 构造函数:pair<T1,T2> p1;//默认构造pair<T1,T2> p2(v1,v2);//两参数构造,注意这个不是explicit的,tuple这一项是explicit的pair<T1,T2> p3(p2);//拷贝构造pair<T1,T2> p4={v1,v2}原创 2020-10-19 15:52:33 · 918 阅读 · 0 评论 -
tuple是快速随意的结构体
一、tuple等价于结构体如果我们希望存储学号int、姓名string和城市string数据集合,vector无能为力,我们可以定义一个结构体:struct info{ int ID, string name, string city};Zhangsaninfo={1,"zhangsan","nanjing"};Lisiinfo={2,"Lisi","Guangzhou"};也可以定义一个tuple对象。tuple<int, string, string> Zhangsa原创 2020-10-16 17:10:28 · 500 阅读 · 0 评论 -
const定义及初始化约束
虽然知道这两个的区别,但是总是混淆他的中文名称。指针和 const 谁在前先读谁 ;*象征着地址,const象征着内容;谁在前面谁就不允许改变。一个是指向方向不变,一个是指向对象不变。英文中是:pointer to const const pointer ...原创 2020-11-01 08:51:58 · 2216 阅读 · 1 评论 -
运算符求值顺序可能不确定
优先级仅规定了表达式的组合方式,而没有对运算对象的求值顺序进行规定。假如我们有两个函数分别是f1和f2。void f1(int &i){ i++;}void f2(int &i){ i++;}使用者这么使用:int main(){ int i=1; }...原创 2020-09-26 10:23:00 · 1053 阅读 · 2 评论 -
左右值属性和引用
一、左值和右值属性C++中,表达式必然是左值和右值中的一掌,右值只读,左值除了有右值的能力外还具有写的能力。常见的const修饰的对象就为右值,字面值常量也为右值。一些运算符对操作的对象左右值有要求:赋值语句。左侧必须为左值,右侧随便。返回为左值。取地址运算符。取地址作用对象既可以是左值也可以是右值,但是最后为右值。解引用。作用对象可以是指针、迭代器和STL类,返回左值;内置和迭代器自增和自减。作用对象是左值,返回结果仍然是左值。decltype返回的结果作用对象的左右值属性有关,如:in原创 2020-09-21 08:53:16 · 540 阅读 · 0 评论 -
类值和类指针的资源管理
#include <iostream>#include <string>#include <memory>using namespace std;class ValueLikeClass{public: //原来构造函数也可以有默认实参,默认实参除了字面值常量 //原来在函数体做的初始化操作都可以放到初始化参数列表中做 //拷贝构造居然可以也在参数化列表里完成虽然看上去不怎么好看 ValueLikeClass(const string& s =原创 2020-09-18 14:16:34 · 118 阅读 · 0 评论 -
类拷贝规则——三/五法则
三/五法则是什么?早些时候,C++对拷贝行为的管理需要通过三个函数完成,其分别是:拷贝构造函数拷贝赋值函数析构函数class A{public: A() { } A& operator=(const A&) {} //rule1 A(const A&) {} //rule2 ~A() {}; //rule3private:};这就叫做“三法则”,随着语言的发展,增加了两个函数,用于更精细的拷贝构造:移动原创 2020-09-17 11:01:33 · 819 阅读 · 0 评论 -
智能指针(二)智能指针的几个问题
智能指针是一个类模板经过实例化后,智能指针就和普通类没有什么区别。构造函数默认构造shared_ptr<T> sp和unique_ptr<T> up指针构造shared_ptr<T> sp(T *)和unique_ptr<T> up(T *),这里默认为explicit拷贝构造注意到指针构造函数被声明为explicit,意味着我们删除了指针形式的任何拷贝构造函数。shared_ptr<T> sp=new T;unique_p原创 2020-05-30 00:09:41 · 1431 阅读 · 0 评论 -
C++中简化类型声明的方式
在C++中有两种简化复杂类型声明的方式:usingtypedef复杂的声明指向数组的指针: double (*p)[10];他复杂吗?复杂,我不仅要记住指针(*)优先级小于数组([ ]),还要使用括号( ( ) )告知编译器我要的是指针。本着减少思考的原则我们应该简化,方法是什么?using或者typedef!using pTenDouble=double(*)[10];//变量名放在等号的左侧typedef double(* pTenDouble)[10];//新名就在原来名字的位置原创 2020-05-23 13:08:51 · 336 阅读 · 0 评论 -
“新”标准下随机数生成方法
这里用到了C++随机数引擎其头文件为,为了随机初始化引擎还用到了<time.h>三步输出一个随机数随机初始化引擎选择合适的分布调用 引擎+分布示例double get_ramdon_double0_2(){ static std::default_random_engine e(static_cast<unsigned>(time(0)));//随机初始化一个引擎 static std::uniform_real_distribution<double&g原创 2020-05-12 19:56:21 · 311 阅读 · 0 评论 -
初识vector内存增长机制
一、vector的特点动态性,空间大小既可以增大亦可以减少;连续性,vector元素序列在空间地址是连续分布的;稳定性,vector元素序列在空间地址是相对固定的。1.1 vector的动态性vector常常被称为动态数组,这里的“动”应该相对于内置数组中的“静”,声明一个内置数组意味着最大容量已经确定,反之,动态数组则可以根据用户的需要进行调整。1.2 vector的连续性ve...原创 2020-05-07 13:33:27 · 522 阅读 · 0 评论 -
std::string插入的方法
std::string的插入位置string插入位置是在下标或者迭代器对应元素的前边,我们知道长度为n的字符串有n+1的插入位置。string str("4396");//s.insert(pos,args)//args: pos stringstring st("here");for(int i=0;i<str.size()+1;i++){ str.insert(i,...原创 2020-04-27 13:19:15 · 5763 阅读 · 1 评论 -
dynamic_cast向上转换总是成功,向下转换有可能成功
一 dynamic_cast在什么时候用?dynamic_cast通常用在基类指针或引用执行某个非虚函数的派生类方法.他是一种安全但是耗时的操作,能够通过一定方法避免使用.二 dynamic_cast 形式dynamic_cast<type *>(e);dynamic_cast<type &>(e);dynamic_cast<type &&a...原创 2020-04-21 22:48:29 · 851 阅读 · 0 评论