第6章 C++语言新特性111417专题一

发布时间 2023-03-24 11:41:09作者: sha_ckle

类型推导:auto/decltype

语法:auto变量名称 = 值;(从值推导)

​ decltype(表达式) 变量名称[=值];(从表达式推导)

功能:自动推导出变量名称的类型。

案例

#include<iostream>
using namespace std;

int main()
{
	auto varl = 355;
    decltype(199.23) var3;
    
    cout << "var1占据字节个数:" << sizeof(var1) << endl;
    cout << "var2占据字节个数:" << sizeof(var2) << endl;
    
    return 0;
}

序列for循环

概念:C++语言当中可以遍历数组、容器、String以及有begin/end函数定义的序列。

案例

#include<iostream>
using namespce std;

int main()
{
	for(const auto var:{43,35,23,64,75,54,57,25,27,78})
        cout << var << " ";
    
    cout << endl;
    
    for(const auto str:{"shg","see","GHI","sge"})
        cout << str << " ";
    
    cout << endl;

	return 0;
}

lambda表达式

概述:C++11中的lambda表示式用于定义并创建匿名的函数对象。我们如何声明lambda表达式完整格式语法如下:[capture list](params list) mutable exception->return type {function body}

案例

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

bool comparefunc(int x, int y)
{
    return x < y;
}

int main()
{
    vector<int>myvr{93,13,255,56,42};
    vector<int>lvec(myvr);
    
    //平时常用的方法如下:
    sort(myvr.begin(), myvr.end(), comparefunc);
    cout << "输出结果为:" << endl;
    for(int it: myvr)
        cout << it << ' ';
    cout << endl;
    
    //下面我们使用lambda表达式
    sort(lvec.begin(), lvec.end(), [](int a, int b)->bool {return a < b;});
    cout << "lambda表达式输出结果为:" << endl;
    for(int il:lvec)
        cout << il << ' ';
    cout << endl;

	return 0;
}

构造函数:委托构造和继承构造

概述:委托构造函数它可以使用当前的类和其他构造函数来协助当前构造函数的初始化操作。

普通构造函数和委托构造函数区别:

  • 它们两都是一个成员初始值列表与一函数体
  • 委托构造函数的成员初始列表只要一个唯一的参数,就是构造函数

当被委托构造函数当中函数体有代码,那么会先执行完函数体的代码,才加回来到委托构造函数。

#include<iostream>
#include<string>
using namespace std;

//创建一个类
class TestC
{
public:
    //普通构造函数
    TestC(string s, int d):data(d),str(s)
    {
        cout << "程序执行:普通构造函数的函数体" << endl;
    }
    
    //委托构造函数
    TestC(int d):TestC("测试TestC(int d)",d)
    {
        cout << "程序执行:委托构造函数的函数体" << endl;
    }
    
    void printdata()const
    {
        cout << "----------------------------"<< endl;
        cout << "str=" << str << endl;
        cout << "data=" << data << endl;
        cout << "----------------------------" << endl;
    }
private:
    int data;
    string str;
}

int main()
{
    TestC objc1("测试普通构造函数:TestC(string s, int d)",345);
    objc1.printdata();
    
    TestC objc2(876);
    objc2.printdata();
    
    //委托构造函数字符串str赋值操作,自己尝试

	return 0;
}

概述:继承构造函数:在C++语言当中的继承关系,只有虚函数可以被继承,而构造函数不可以是虚函数,所以构造函数不能被继承,但是我们可以通过某种手段,达到继承效果。

#iclude<iostream>
using namespce std;

struct A
{
    void func(double d)
    {
        cout << "Base:" << d << end;
    }
};

struct B :A{
	using A::func;//C++11 标准当中利用using关键字特点:使构造函数可以被继承。
    void func(int i)
    {
        cout << "派生类B:" << i << endl;
    }
};

int main()
{
	A a;
    a.func(45);
    
    B b;
    b.func(87);
    
    return 0;
}

容器:array/forward_list/tuple

C++ array(STL array)容器,array容器是C++11标准中新增的序列容器。

#include<istream>
//要使用array容器就必须加上头文件
#include<array>

using namespace std;

int main()
{
    std::array<int, 5>values{};
    //初始化values容器
    for(int i = 0; i < values.size(); i++)
    {
        values.at(i) = i;
    }
    
    //通过get()重载函数输出指定位置元素值
    cout << "输出结果为:" << get<4>(values) << endl;
    
    return 0;
}

forward_list是C++新增加一类容器,其底层实现和list容器类似,采用的也是链表结果,只是forward_list使用的单向链表,而list使用的双向链表。

#include<iostream>
#include<forward_list>
using namespace std;

int main()
{
    std::forward_list<int> values{10,20,30};
    values.emplace_front(40);
    cout << "输出结果1为:" << endl;
    for(auto it = values.begin(); it != values.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    values.emplace_after(values.before_begin(),50);
    cout << "输出结果2为:" << endl;
    for(auto it = values.begin(); it != values.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    values.reverse():
    cout << "输出结果3为:" << endl;
    for(auto it = values.begin(); it != values.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    return 0;
}

垃圾回收机制

  1. 标准C++没有垃圾回收机制原因:系统开销、耗内存、替代方法、没有共同基类。
  2. c/c++中经典垃圾回收算法:引用计数算法、标记-清除算法、节点拷贝算法。

正则表达式基础

​ 正则表达式,又称为规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

​ 许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex",单数有regrex\regex,复数有regexps\regexes\regxen。

  1. 符号

    正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义,下满会给予解释。

    最简单的情况下,一个正则表达式看上去就是一个普通的查找串。例如,正则表达式"testing"中没有包含任何元字符,它可以匹配"testing"和"testing123"等字符串,但是不能匹配"Testing"。

    要想真正的用好正则表达式,正确的理解元字符是最重要的事情。下表列出了所有的元字符和对它们的一个简短的描述。

    元字符 描述
    \ 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\n”匹配\n。“\n”匹配换行符。序列“\”匹配“\”而“(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。
    ^ 匹配输入行首。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
    $ 匹配输入行尾。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
    * 匹配前面的子表达式任意次。例如,zo能匹配“z”,也能匹配“zo”以及“zoo”。等价于{0,}。
    + 匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
    ? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价于{0,1}。
    {n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
    {n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
    {n,m} mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
    ? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。例如,对于字符串“oooo”,“o+”将尽可能多地匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少地匹配“o”,得到结果 ['o', 'o', 'o', 'o']
    .点 匹配除“\n”和"\r"之外的任何单个字符。要匹配包括“\n”和"\r"在内的任何字符,请使用像“[\s\S]”的模式。
    (pattern) 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“(”或“)”。
    (?:pattern) 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
    (?=pattern) 非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
    (?!pattern) 非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。
    (?<=pattern) 非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。*python的正则表达式没有完全按照正则表达式规范实现,所以一些高级特性建议使用其他语言如java、scala等
    (?<!pattern) 非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。*python的正则表达式没有完全按照正则表达式规范实现,所以一些高级特性建议使用其他语言如java、scala等
    x|y 匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”则匹配“zood”或“food”。
    [xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
    [^xyz] 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”任一字符。
    [a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身.
    [^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
    \b 匹配一个单词的边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”;“\b1_”可以匹配“1_23”中的“1_”,但不能匹配“21_3”中的“1_”。
    \B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
    \cx 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
    \d 匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持
    \D 匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持
    \f 匹配一个换页符。等价于\x0c和\cL。
    \n 匹配一个换行符。等价于\x0a和\cJ。
    \r 匹配一个回车符。等价于\x0d和\cM。
    \s 匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
    \S 匹配任何可见字符。等价于[^ \f\n\r\t\v]。
    \t 匹配一个制表符。等价于\x09和\cI。
    \v 匹配一个垂直制表符。等价于\x0b和\cK。
    \w 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。
    \W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
    \xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。
    \num 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
    \n 标识一个八进制转义值或一个向后引用。如果**n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n**为一个八进制转义值。
    \nm 标识一个八进制转义值或一个向后引用。如果*nm之前至少有nm个获得子表达式,则nm**为向后引用。如果*nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若nm均为八进制数字(0-7),则**nm将匹配八进制转义值nm
    \nml 如果n为八进制数字(0-7),且ml均为八进制数字(0-7),则匹配八进制转义值nml
    \un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。
    \p 小写 p 是 property 的意思,表示 Unicode 属性,用于 Unicode 正表达式的前缀。中括号内的“P”表示Unicode 字符集七个字符属性之一:标点字符。其他六个属性:L:字母;M:标记符号(一般不会单独出现);Z:分隔符(比如空格、换行等);S:符号(比如数学符号、货币符号等);N:数字(比如阿拉伯数字、罗马数字等);C:其他字符。*注:此语法部分语言不支持,例:javascript。
    \< \> 匹配词(word)的开始(<)和结束(>)。例如正则表达式<the>能够匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:这个元字符不是所有的软件都支持的。
    ( ) 将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
    | 将两个匹配条件进行逻辑“或”(or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。
  2. 速记技巧

    . [ ] ^ $

    四个字符是所有语言都支持的正则表达式,所以这四个是基础的正则表达式。正则难理解因为里面有一个等价的概念,这个概念大大增加了理解难度,让很多初学者看起来会懵,如果把等价都恢复成原始写法,自己书写正则就超级简单了,就像说话一样去写你的正则了:

    等价:

    等价是等同于的意思,表示同样的功能,用不同符号来书写。

    ?,*,+,\d,\w 都是等价字符

    ?等价于匹配长度{0,1}

    *等价于匹配长度{0,}

    +等价于匹配长度{1,}

    \d等价于[0-9]

    \D等价于[^0-9]

    \w等价于[A-Za-z_0-9]

    \W等价于[^A-Za-z_0-9]

    常用运算符与表达式:

    ^ 开始

    () 域段

    [] 包含,默认是一个字符长度

    [^] 不包含,默认是一个字符长度

    {n,m} 匹配长度

    . 任何单个字符(. 字符点)

    | 或

    \ 转义

    $ 结尾

    [A-Z] 26个大写字母

    [a-z] 26个小写字母

    [0-9] 0至9数字

    [A-Za-z0-9] 26个大写字母、26个小写字母和0至9数字

    , 分割

    .

    分割语法:

    [A,H,T,W] 包含A或H或T或W字母

    [a,h,t,w] 包含a或h或t或w字母

    [0,3,6,8] 包含0或3或6或8数字

    语法与释义:

    基础语法 "^([]{})([]{})([]{})$"

    正则字符串 = "开始([包含内容]{长度})([包含内容]{长度})([包含内容]{长度})结束"

    ?,,+,\d,\w 这些都是简写的,完全可以用[]和{}代替,在(?:)(?=)(?!)(?<=)(?<!)(?i)(?)(+?)这种特殊组合情况下除外。

    初学者可以忽略?,*,+,\d,\w一些简写标示符,学会了基础使用再按表自己去等价替换

    实例:

    字符串;tel:086-0666-88810009999

    原始正则:"^tel:[0-9]{1,3}-[0][0-9]{2,3}-[0-9]{8,11}$"

    速记理解:开始 "tel:普通文本"[0-9数字]{1至3位}"-普通文本"[0数字][0-9数字]{2至3位}"-普通文本"[0-9数字]{8至11位} 结束"

    等价简写后正则写法:"^tel:\d{1,3}-[0]\d{2,3}-\d{8,11}$" ,简写语法不是所有语言都支持。

  3. 检验数字的表达式

    \1. 数字:^[0-9]*$

    \2. n位的数字:^\d{n}$

    \3. 至少n位的数字:^\d{n,}$

    \4. m-n位的数字:^\d{m,n}$

    \5. 零和非零开头的数字:^(0|[1-9][0-9]*)$

    \6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$

    \7. 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})?$

    \8. 正数、负数、和小数:^(-|+)?\d+(.\d+)?$

    \9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$

    \10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$

    \11. 非零的正整数:^[1-9]\d$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]*$

    \12. 非零的负整数:^-[1-9][]0-9"$ 或 ^-[1-9]\d$

    \13. 非负整数:^\d+$ 或 ^[1-9]\d*|0$

    \14. 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$

    \15. 非负浮点数:^\d+(.\d+)?$ 或^[1-9]\d.\d|0.\d[1-9]\d|0?.0+|0$

    \16. 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d.\d|0.\d[1-9]\d))|0?.0+|0$

    \17. 正浮点数:^[1-9]\d.\d|0.\d[1-9]\d$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$

    \18. 负浮点数:^-([1-9]\d.\d|0.\d[1-9]\d)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$

    \19. 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d.\d|0.\d[1-9]\d|0?.0+|0)$

  4. 检验字符的表达式

    \1. 汉字:^[\u4e00-\u9fa5]{0,}$

    \2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$

    \3. 长度为3-20的所有字符:^.{3,20}$

    \4. 由26个英文字母组成的字符串:^[A-Za-z]+$

    \5. 由26个大写英文字母组成的字符串:^[A-Z]+$

    \6. 由26个小写英文字母组成的字符串:^[a-z]+$

    \7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$

    \8. 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$

    \9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$

    \10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$

    \11. 可以输入含有%&',;=?$"等字符:[%&',;=?$\x22]+ 12 禁止输入含有的字符:[^\x22]+

  5. 特殊需求表达式

    \1. Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$

    \2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?

    \3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$

    \4. 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$

    \5. 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$

    \6. 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}

    \7. 身份证号(15位、18位数字):^\d{15}|\d{18}$

    \8. 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$

    \9. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$

    \10. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$

    \11. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$

    \12. 日期格式:^\d{4}-\d{1,2}-\d{1,2}

    \13. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$

    \14. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$

    \15. 钱的输入格式:

    \16. 1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$

    \17. 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$

    \18. 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$

    \19. 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$

    \20. 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$

    \21. 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$

    \22. 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$

    23 8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

    \24. 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

    \25. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$

    \26. 中文字符的正则表达式:[\u4e00-\u9fa5]

    \27. 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))

    \28. 空白行的正则表达式:\n\s*\r (可以用来删除空白行)

    \29. HTML标记的正则表达式:<(\S?)[^>]>.?</\1>|<.? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)

    \30. 首尾空白字符的正则表达式:\s*|\s*$或(\s)|(\s$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)

    \31. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)

    \32. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)

    \33. IP地址:\d+.\d+.\d+.\d+ (提取IP地址时有用)

    \34. IP地址:((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))

#include<iostream>
#include<string>
#include<regex>

int main()
{
    std::regex string_reg("[1-9](\\d{5,11})");
    
    //std::string strtest("666");
    std::string strtest1("12345213242");
    
    std::smatch matchresults;
    
    //正则匹配
    if(std::regex_match(strtest, matchresults, string_reg))
    {
        std::cout << "Match:" << std::endl;
        //输出表达式
        for(size_t i = 0; i < matchresults.size(); i++)
        {
            std::cout << matchresults[i] << std::endl;
        }
    }
    else
    {
        std::cout << "Not Match:" << std::endl;
    }
    
    return 0;
}

智能指针:shared_ptr/unique_ptre/weak_ptr ->头文件<memory>

unique_ptr智能指针:独占指针(内存占为己有,不支持拷贝和赋值)

#include<iostream>
#include<memory>
using namesapce std;

int main()
{
    std::unique_ptr<int> p1(new int(24));
    cout << "*p1=" << *p1 << endl;
    
    std::unique_ptr<int> p2 = std::move(p1);
    cout << "*p2=" << *p2 << endl;
    
    p2.reset();//显示释放内存
    p1.reset():
    
    std::unique_ptr<int>p3(new int(678));
    p3.reset(new int(666));//绑定动态对象
    coue << "*p3=" << *p3 << endl;
    
    p3 = nullptr; //显示销毁指向对象,同时智能指针变为空,p3.reset()
    
    std::unique_ptr<int> p4(new int(999));
    int *p = p4.release();//只是释放控制权,不会释放内存
    cout << "*p=" << *p << endl;
    
    delete p;//释放堆区资源数据
    
    
    return 0;
}

shared_ptr智能指针(共享拥有同一个堆分配对象的内存,支持复制与赋值操作)。

#include<iostream>
#include<memory>
using namespace std;

int main()
{
    shared_ptr<int> p1(new int(456));
    shared_ptr<int> p2 = p1;
    cout << "p2=" << p2.use_count() << endl;//2
    
    cout << "*p1=" << *p1 << endl;
    cout << "*p2=" << *p2 << endl;
    cout << "p2=" << p2.use_count() << endl;//2
    
    p1.reset();
    cout << "p2=" << p2.use_count() << endl;//1
    
    return 0;
}

make_share函数:最安全的分配和使用动态内存的方法。

weak_ptr智能指针:配合shared_ptr而引入的一种智能指针协助share_ptr工作。它的构造和析构不会引起引用计数的增加或减少。weak_ptr并不拥有资源的所有权,所以不能直接使用资源。可以从一个weak_ptr构造一个shared_ptr以取得共享资源的多有权。

#include<iostream>
#include<memory>
using namespace std;

int main()
{
    share_ptr<int> p1(new int(466));
    share_ptr<int> p2 = p1;
    weak_ptr<int> wp = p1;
    cout << "count=" << wp.use_count() << endl;
    cout << "*p1=" << *p1 << endl;
    cout << "*p2=" << *p2 << endl;
    
    return 0;
}

关键字:nullptr/constexpr

  1. nullptr关键字,它的出现为代替NULL。

    #include<iostream>
    using namespace std;
    
    void Func(char *pc)
    {
        printf("调用此函数为:char*\n");
    }
    
    void Func(int intnumber)
    {
        printf("调用此函数为:int\n");
    }
    
    int main()
    {
    	Func(0);
        Func(nullptr);
    
    	return 0;
    }
    
  2. constexpr关键字:

    #include<iostream>
    using namespace std;
    
    int main()
    {
        int x = 400;
        int y = 2000;
        cout << "x=" << x << endl;
        
        constexpr int *p = &x;
        *p = 129;
        cout << "x=" << x << endl;
        
        p = &y;//错误
        
        return 0;
    }
    

共享内存互斥量mutex

服务端程序:

  1. 创建共享内存区域部分
  2. 内存映射到当前应用进程进程
  3. 写入数据信息

客户端程序:

  1. 打开共享内存区域部分
  2. 内存映射到当前应用程序进程
  3. 读出数据信息
#include<iostream>
#include<Windows.h>
using namespace std;

#define BUF_SIZE 1024

int main()
{
    //共享数据信息
    char = szBuffer[] = "零声教育C/C++企业级项目实战课程";
    
    //创建共享文件句柄
    HADLE hmFile = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,BUF_SIZE,L"VICO");
    
    //映射
    LPVOID lpbase = MapViewofFile(hmFile,FILE_MAP_ALL_ACCESS,0,0,BUF_SIZE);
    
    //将数据拷贝到共享内存
    strcpy((char*)lpBase,szBuffer);
    cout << "\n服务器程序端:" << (char*)lpBase << endl;
    
    //线程挂起等待其他线程读写数据
    Sleep(20000);
    
    //删除文件映射
    UnmapViewOfFile(lpBase);
    
    //关闭内存映射文件对象句柄
    CloseHandle(hmFile);
    
    return 0;
}
#include<iostream>
#include<Windows.h>
using namespace std;

#define BUF_SIZE 1024

int main()
{
    HADLE hmfile = OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,L"VICO");
    
    if(hmfile)
    {
        LPVOID lpBase = MapViewOfFile(hmfile, FILE_MAP_ALL_ACCESS,0,0,0);
        
        char szBuffer[BUF_SIZE] = {0};
        strcpy(szBuffer,(char*)lpBase);
        cout << "\n客户端程序端:" << szBuffer;
        
        UnmapViemOfFile(lpBase);
        
        CloseHandle(hmfile);
    }
    else
    {
        printf("\n打开共享内存失败,请检查操作");
    }
    
    return 0;
}