C++标准库体系结构&参数化模型

C++标准库体系结构&参数化模型

C++程序运行原理
链接

一般我们编写的程序都会引用基本的库函数,因此在运行程序之前还要把库函用定义好的目标代码替换,这个过程称为链接。就是把自己写的源代码的目标文件与库函数的目标文件组合起来,生成最终的可执行文件。链接由链接器完成。除了ascii码值表示的文件,其余的都是二进制文件,比如hello中用到了printf函数,这是标准c库的函数,存在于一个名为printf.o的单独编译好的目标文件中,这个文件必须以某种方式合并到我们编译好的的目标文件中。链接器(ld)程序负责处理这种合并,结果得到hello文件,它是可执行目标文件,可以被加载到内存中,由系统执行。

​ 转换完成之后就是执行了。在unix系统中,shell是一个命令行解释器,输出一个提示符,等待用户输入然后执行命令。如果输入的第一个单词不是一个内置的shell命令,shell将其解释为可执行文件,比如输入./hello,它将加载并运行这个文件。hello在屏幕上输出信息,然后终止。shell输出一个提示符,等待下一个输入的命令行。具体的过程为:初始时,shell执行它的指令,等待输入。用户输入字符创“./hello”后,shell将字符逐一读入寄存器,然后存放到存储器中,敲回车键后,shell知道用户结束命令输入。然后shell执行一系列的指令来加载可执行的hello文件,将hello目标文件的代码和数据从磁盘复制到主存,数据包含输出的字符串"HELLO,WORLD\n"。一旦目标文件hello中的代码和数据被加载到主存,处理器开始执行main的机器语言指令,将字符串从主存拷贝到寄存器,并输出到屏幕上。

​ 由于涉及大量的主存,磁盘,寄存器通信,故产生了cache等缓冲提高速度的设备,减少通信阻塞。

​ 为了减少用户的负担,操作系统对计算机硬件资源进行了抽象,产生了进程,线程,虚拟地址等概念。进程是程序的一次执行,是操作系统分配资源的单位,多个进程是可以并发执行的,并发执行实际上每个时刻执行的还是一个进程,只不过进程间切换的速度比较快,给人的感觉是并发执行。操作系统为每个进程保存执行的状态信息,称为上下文,包括pc和寄存器文件当前值,主存内容等等。切换进程时,发生上下文切换。一个进程中可以有多个线程执行单元,每个线程都运行在进程的上下文中,共享同样的代码和数据,由于网络服务器等应用对并行处理的需求越来越大,多线程模型也越来越重要。虚拟地址为每个进程提供了一个假象,即每个进程都在独占主存,每个进程看到的是一致的存储器,称为虚拟地址空间。虚拟地址空间是由大量的准确定义的区构成,linux从低地址到高地址依次为:程序代码和数据;堆;共享库;栈;内核虚拟存储器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

C++模板

类模板

函数模板

成员函数模板

成员类模板

模板参数模板

Templates四个条款及其使用
标准库体系结构(源码分析)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

容器#

迭代器

分配器

重新绑定

rebind用法及其前后脉络

算法 #

仿函数

适配器

concept

关于字符串和转义字符

字符串:
  1. 字符长度:/0不包含进字符长度strlen(name),不论多少个/0结果一样,但占的空间sizeof(name)还是要算进去 。
转义字符:
  1. 用法:
//1.表示字符串里的特殊字符
 char stra[]={"\"C++\""};
  //2.路径表示 
  char path[]={"C:\\tu\\text.c"}
  //相当于
  char path[]={"C:/tu/text.c"}
  • 转义字符可用于单个字符’、\t,也可以用三位八进制(0-最大0377)和两位十六进制(0-最大0xff)的数字,即将对应十进制ASC值转换成字符,如\141,十进制为97,是a的asc码值,故表示的是a;在字符串中占一个字节。且这种表示法的数字是有限制的,如八进制里不能出现8、且ASC本身只用一个字节去表示字符,故不管是哪个进制都不能超过255(10)

选择语句

if-else

循环语句

  • while(){}//必加{}
int i;
while(i<100){
printf(" ");
i++;
}
  • do{}while()
int n;
do
{
printf("%d",n);
n--;
}while(n<10)

  • for(; ; )
for(int i=1;i<=10;i++){
printf("%d",n);
}

程序执行过程中的内存资源分配

在这里插入图片描述
编译和链接与执行是分开的,如果没有编译完成,那么不存在程序被装在用户存储区,全局变量也没有被装进.data区

数组

函数

&:带&函数形参,使用并接收返回值,而 & 叫做引用符,它是 C++ 的内容(目前多数 C 语言编译器也能使用),它可以引用主函数中 x 的地址,而不在调用的函数栈帧中开辟空间,这样就可以对主函数中的 x 进行修改。

效果类似于使用并接收返回值。

*与&:

//指针传递
void swap(int *a, int *b){
	cout<<"形参指针a的地址 = "<< a <<endl;
	cout<<"形参指针b的地址 = "<< b <<endl;
    int tmp = *a;
	*a = *b;
	*b = tmp;
}

int main(){
	int a = 5;
	int b = 10;
	cout<<"实参变量a的地址 = "<< &a <<endl;
	cout<<"实参变量b的地址 = "<< &b <<endl;
	cout<<"实参变量a的值 = "<< a <<endl;
	cout<<"实参变量b的值 = "<< b <<endl;
	//调用函数,指针传递方式
	swap(&a, &b);
	cout<<"实参变量a的值 = "<< a <<endl;
	cout<<"实参变量b的值 = "<< b <<endl;
	getchar();
	return 0;
}
//若采用指针传递的方式,我们在函数定义和函数声明时使用 *来修饰形参,表示这个变量是指针类型;在进行函数调用时,使用 & 来修饰实参,表示是将该变量的地址作为参数传入函数。

指针

地址小端存储
系统如何访问指针

结构体:

封装的类型,相对于内置类型的定义,需要用大括号初始化;

//定义
struct Student
{
char id[10];
char name[10];
char sex[5];
int age;
};//以上为结构体设置,相当于声明一种类型,须带分号
//}Stud;与struct Student Stud;等价,若在函数外声明相当于声明了一个全局结构体变量

//使用
 struct Student stud={"02434","wxinxi","man",21};
 //stu只是一个变量,不是一个对象
 //结构体只是属性的集合,默认为公有,而类定义的对象是一个属性与方法的集合;
 stud.age;//访问
struct Student *stup=&stud;
(*stup).id;
sp->id;//指针访问成员运算符

文件

1标准文件:标准输出文件stdin:显示器printf(),putchar()
标准输入文件stdout:键盘scanf(),getchar()
标准错误文件:显示器

在这里插入图片描述
缓冲区
cpu从键盘读?从缓冲区读?(CPU直接访问键盘的速度太慢)
读缓冲区:CPU访问到getchar,终止对getchar的访问,转而去处理别的任务,当getchar将数据全部读到缓冲区时,CPU才会回来处理


char ch;
scanf("%c",ch);
ch=getchar();
while(getchar()!="\n");{
sum=sum+1;
}
printf("sum:%d\n",sum);

2.宏常量<stdio.h>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • EOF:可以输入多行数据,换行为每行的标志,当键盘输入ctrl+c,产生EOF,结束标志产生

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

面向对象

封装(属性+操作)

继承(对象种类不同,而有继承)

继承(继承了属性和方法)中保护与私有区别:在子类中保护可以访问,私有不能访问
若父类没有默认或缺省构造函数,必须在子类中显式调用父类构造进行初始化
多继承和多层继承

多态

多态四种:(覆盖,基类的指针或引用)
重载多态(函数,运算符)
包含多态(虚函数 virtual)
强制多态(强制类型转换 _cast)
参数多态(模板,传过去参数不同,运用函数不同)

泛型编程(数据跟操作分开,操作可以对多种类型操作)

动态联编和静态联编

动态联编:编译时刻不能确定调用哪个

条件:父子,虚函数,指针或引用

c.f(1);//
c.f();//error ,不能直接调用,要通过基类的指针或者引用
//隐藏规则 :A--子函数同名不同参,基类为虚||同名同参基类不为虚,基类的函数被隐藏,不能直接通过子类对象直接调用基类的同名函数         
//重载规则:同域,同名不同参,const
//覆盖规则:父子关系-不同域,同名同参,基类必须为虚
//用函数指针数组--把函数的地址存放在数组里
int fn0(int n){
    return 0;
}
int fn1(int n){
  static int(*p[n])()={fn0,fn1};
  return p[!!n]+(n-1);
}
int main(){
    cout<<fn1(100)<<endl;
}
//构造函数求解 用对象数组构建n个对象,构造函数会被调用n次,用到静态变量  
class A{
 private:
    static int n;
    static int sum;
 public:
    A(){
        n++;
        sum+=n;
    }
    int getsum(){
        return sum;
    } 
};
int main(){
    A a[100];
    cout<<a[0].getsum<<endl;
}
//用虚函数求解
class A;
A*Arr[2];
class A{
 public:
    virtual fun(int n){
        return 0;
    } 
};
class B:public A{
    public:
    int fun(int n){
        return Arr[!!n]->fn(n-1)+n;
    }
};
void main(){
    A a; 
    B b;
    Arr[0]=&a;
    Arr[1]=&b;
    cout<<Arr[1]->fun(100)<<endl; 
}

//用b[a[i]]++;找票据问题、排序问题
int main(){
    int a[15]={1,3,3,4,6,7,7,8,0,0,5,4,3,3,2};
    for(int i=0;i<14;i++)b[a[i]]++;
    for(int i=0;i<=14;i++){
        for(int j=0;j<b[i];j++)
            cout<<i<<" ";
        cout<<endl;
    }
}      
纯虚函数:

有纯虚函数类的类叫抽象类,不实例化对象,但可以定义指向抽象类的指针或引用,做家族顶尖,让子类去实现多态 =0的本质是将虚函数表指针指向nullptr

​ 避免父类函数无法实现,而定义了对象,无法调用

Shape *p[4]={A a;B b;C c};

高质量C++编程指南

多继承
class A{//sizeof(A)=4;
    virtual void fnA(){};
};
class B{//sizeof(B)=4;
    virtual void fnB(){};
};
class C{//sizeof(C)=4;
    virtual void fnC(){};
};
class D:public A,public B,public C   {//sizeof(D)=12;
    virtual void fnD(){};   
}
class E:public A(){//sizeof(E)=8
    virtual void fnD(){};   
};

image-20230420193720258

虽然加到了A部分的下面,但是并没有改变A的类的虚表,只是在D对象上的改动

虚函数小结
  • 多态得是同名同参同返回值类型。基类返回基类指针,派生类返回派生类指针,这是被允许的一个例外(协变)
  • 虚函数只能用在类中
  • 类的静态成员不能作为虚函数,静态成员是类每个对象都有的,而虚函数的实现是根据具体对象的不同而决定的
  • 构造函数和拷贝构造函数是设置虚指针的,且不能作为虚函数,析构函数一般是作为虚函数的,实现撤销对象的多态性,合理释放空间,实构造,虚析构
  • 在运行时的多态,执行速度慢一些,更追求通用性
  • 运行时多态的条件
  • virtual 放在声明前,不能放在纯定义前(在.cpp里面)
//析构什么时候生效?//执行 delete对象指针
//派生类析构函数没有执行 为什么 运行时把全部的析构函数的函数名全部改为了destuctor
void test(Persen*p){
   delete p; 
}
void main(){
    test(s);
}
//把父类的析构函数写成虚的  
运行时多态原理

虚函数指针表存在于只读数据段

vfptr存储在对象中

RTTI 运行时类型识别 内有typeid运算符,可以返回这个指针或对象的实际类型,

typeid作用是运行时获得变量的类型,可以用于静态类型(编译时获得,如非引用)和动态类型(运行时识别,如引用)

//多态的3个例子
//1.
A::fn (int a=10){cout<<"A:fn  a="<<a<<endl;}
B::fn (int b=20){cout<<"B:fn  b="<<b<<endl;}
//输出:
//A:fn a=10
//B:fn b=10
//虚函数的默认参数是静态绑定,再派生类中重新定义虚函数时,不重新定义继承而来的缺省参数,基类的默认值覆盖了子类的默认值,默认值是在编译期间使用的,虚表是运行时刻创建的
//2.类内调用函数的运行时多态
//3.虚表在哪里开辟空间
class Parent{
    public:
    virtual fn(){};
};
int main(){
Parent pa;
printf("虚表:%p\n",*((int*)(&pa)));
//在常量区
}
多态:强制类型转换
动态联编和静态联编

一、填空题()

1.面向对象的特征__继承 封装 多态________________。

3.定义重载函数时,应在__参数列表_____上有所不同。

const mutable ++

  1. 类是用户定义的类型,具有类类型的变量称作_对象______。

类本身不占大小,只是告诉系统应该给对象开辟多大的空间

类的大小

空:一个字节 非空:静态,对齐,指针

  1. 当一个成员函数被调用时,该成员函数的___this指针____指向调用它的对象。

接收本对象地址,静态成员函数是没有this指针的

  1. 拷贝构造函数通过_本类对象的常引用______来初始化创建中的对象。

引用传递:传递一个副本过去

指针传递:要加地址符int *P test(&p)//二级指针

Fun(int*&p2)//&p2是别名

Void Test1(int(&a)[4])//传的是整个数组

Void Test2(int a[1000])//传的是首地址,一般写int *a

Test1(arr);

Test2(arr);

三种形式:(1)用类的一个对象去初始化另一个对象时

(2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用

(3)当函数的返回值是类的对象或==引用时

7.在C++中有二种__参数传递_____方式即值传递和____引用___传递。

8.在C++中调用.C的函数需要加(兼容转化)extern”C”和#ifdef cppplusplus_______

二、完成程序题()

1.在下面程序的底画线处填上适当的字句,使该程序执行结果为60。

class base{int X;

public∶

void init (int initX){X=initX; }

int Getnum() {return X+7; } }

void main()

{base test;_

___test.init(53);

cout<<test.Getnum();

}

2.分析下面程序的正确性

void test()

{

​ const int x = 10;

​ int* p1 = &x;//error *p时会出错

​ const int* p2 = &x;//指向常量的指针,通过这个指针不能修改x,p2可变

​ int* const p3 = &x;//error 声明指针类型为const,p3不可变,指针指向的值为int型*p时出错

const int* const p3 = &x;

​ int num[x] = { 1,2,3,4,5};//ok

​ char str[]{ “helloworld” };//ok

​ int b(10);//ok

​ int c{ 20 }//ok

auto int aa;//error

auto bb;//bb得有值

auto pp = new auto(10);//???

}

  1. 分析下面程序

class Test

{

public:

​ Test(int i = 0, int j) :m_j(j), m_i(m_j) {}

​ void Print() { cout << m_i << " " << m_j << endl; }

private:

​ int m_i;

​ int m_j;

};

int main()

{

​ Test tst(4, 6);

​ tst.Print();//随机值 6

​ Test tst1(5);

​ Tst1.Print();//随机值 0

}

4.在下列程序的空格处填上适当的字句,使输出为:0,8,5。

# include <iostream.h>

# include <math.h>

class Magic{

double x;

public∶

Magic(double d=0.00)∶x(fabs(d)){} //双精度绝对值

operator+(const Magic&c){return Magic(sqrt(xx+c.xc.x));}

friend ostream &operator<<(ostream & os,Magic c);

};

ostream &operator<<(ostream & os,Magic c){return os<<c.x;}

void main()

{Magic ma;

cout<<ma<<’,’<<Magic(-8)<<’,’<<ma+Magic(-3)+Magic(-4);

}

ma 0

-8 8

Ma±3 ±4 5

三、简答题()

  1. 简述引用和指针

引用是给变量取一个别名,跟原来的变量名没有区别,指针是用来存放指向变量地址的

  1. C++的三大特性是什么?请简单描述。

面向对象&面向过程

继承,多态,封装

  1. 谈谈对this指针的理解。

对象创建时,会伴随生成一个隐含的指针,

  1. 函数实参怎么传给形参?形参有没有开辟内存?如果形参开辟内存,在哪里开辟的?

函数的返回值怎么返回到调用方函数?函数返回后怎么知道从哪条语句开始继续执行?

调用函数时,会在这个被调函数的栈帧中给形参开辟内存,形参会把实参的值复制到对应形参,函数调用中的返回值是放在一个临时变量中的,这个临时变量可能存在于寄存器中,也可能在栈中预先分配的一段空间中(因为编译器根据函数拥有返回值会预先分配空间),函数返回时,再把临时变量的值拿出来,放到应赋给的值所在的空间中(如果有赋值的话)。

CPU执行程序时,并不知道整个程序的执行步骤是怎样的,完全是“走一步,看一步”。前面我们提到过,CPU都是根据PC中存放的指令地址找到要执行的语句。函数返回时,是“从哪里离开,就回到哪里”。但是当函数要从被调函数中返回时,PC怎么知道调用时是从哪里离开的呢?答案就是——将函数的“返回地址”保存起来。因为在发生函数调用时的PC值是知道的。在主调函数中的函数调用的下一条语句的地址即为当前PC值加1,也就是函数返回时需要的“返回地址”。我们只需将该返回地址保存起来,在被调函数执行完成后,要返回主调函数中时,将返回地址送到PC。这样,程序就可以往下继续执行了。

四、综合应用题()

1.分析下列程序可能的输出结果。)

# include “iostream”

class Test

{private∶

int num;

float fl;

public∶

test( );

int getint( ){return num;}

float getfloat( ){return fl;}

~test( );

};

test∶∶test( );

{cout<<″lnitalizing default″<<endl;

num=0;fl=0.0;

}

test∶∶~test( )

{cout<<″Desdtructor is active″<<endl;}

int main( )

{test array[2];

cout<<array[1].get int ( )<<″ ″<<array[1].getfloat()<<endl;

}

五、编程题()

1.写一个字符串类(String),要求至少要有赋值操作符,copy构造函数, +操作符。

class String{
    private:
    char*str[];
    public:
    String(const String &other){
        if(otherstring==*this){
            return *this;
        }
        else{
            m_string=new char[strlen(other.m_string)+1];
            strcpy(m_String,other.m_String);
            return *this;
            }
    }
    String& operator+(String &s){
        if(otherstring==*this){
            return *this;
        }
        else{
            m_string=new char[strlen(otherstring.m_string)+1];
            strcpy(m_String,other.m_String);
            return *this;
            }
       s.str=str;}
    String& operator=(String &s){
       s.str=str;
    }
};
#include<iostream>
using namespace std;
class String
{
public:
	String(const char *str=NULL);            //普通构造函数
	String(const String &other);             //复制构造函数
	~String(void);                           //析构函数
	String & operator=(const String &other);//赋值函数
private:
	char *m_String;                        //私有成员,保存字符串
};
String::String(const char *str)
{
	cout<<"普通构造函数"<<endl;
	if(str==NULL)                         //如果str为空,存空字符串
	{
		m_String=new char[1];             //分配一个字节
		*m_String='\0';                  //将之赋值为字符串结束符
	}
	else
	{
		m_String=new char[strlen(str)+1]; //分配空间容纳str内容
		strcpy(m_String,str);             //赋值str到私有成员 
	}
}
String::String(const String &other)
{
	cout<<"复制构造函数"<<endl;
	m_String=new char[strlen(other.m_String)+1];
	strcpy(m_String,other.m_String);
}
String::~String(void)
{
	cout<<"析构函数"<<endl;
	if(m_String!=NULL)                    //如果m_String 不为NULL,释放堆内存
	{
		delete [] m_String;              //释放后置为NULL
		m_String=NULL;
	}
}
String & String::operator =(const String &other)
{
	cout<<"赋值函数"<<endl;
	if(this==&other)                   //如果对象与other是同一个对象
	{
		return *this;                  //直接返回本身
	}
	delete [] m_String;
	m_String=new char[strlen(other.m_String)+1];
	strcpy(m_String,other.m_String);
	return *this;
}
int main()
{
	String a("hello");           //调用普通构造函数
	String b("word");            //调用普通构造函数
	String c(a);                 //调用复制构造函数
	c=b;                         //调用赋值函数
	return 0;
}

运算符重载
//#include<iostream>
//
//using namespace std;
#if 0
class A
{
public:
	A(int i = 0,int j=0):m_i(i),m_j(j){}
	A operator+(const A& s)
	{
		return A(m_i + s.m_i, m_j + s.m_j);
	}
	void print()
	{
		cout << "m_i=" << m_i << "m_j=" << m_j << endl;
	}
	friend A operator-(const A& a, const A& b);
	A& operator++(int) {//前加加
		++this->m_i;
		++this->m_j;//++m_j//ok
		return *this;
	}
	A operator=() {}
​	A operator++() {return A(m_i++,m_j++);}int m_i;int m_j;
};
A operator-(const A& a, const A& b) {return(a.m_i - b.m_i, a.m_j - b.m_j);
}
int main() {
​	A a(10, 20);
​	A b(20, 30);(a + b).print();

}
#endif
STL
  • 模板库Standard Template Library–泛型编程 :类、函数

  • 容器:vector

  • 算法:sort(a,a+n,greater()) copy find(a,a+n,5) find_if(a,a+n,greter5) reverse swap() swap_ranges()
    count(a,a+5,2) count(a,a+5,less5()) include(a,a+10,b,b+5) merge(a,a+5,b,b+5,c)

  • 迭代器:相当于指针,对容器操作

  • –仿函数:把一个对象(类有重载的小括号)当作算法的函数参数放进去,是泛型编程的一个例子

    string是容器类,容器类有通用算法
    	查find rfind
    	比int ret=s.compare(s1)相对应的asc11码值--= : 0  >: 1   < : -1
    	子串 s2=s.substr(1,4)--1:偏移量  4:个数
    	插 insert(0,"kkk")
    	擦
    
Student*p=new Student//p指向new出来的对象
Student*q=(Student*)malloc(sizeof(Student));
拷贝构造:用旧对象创造新对象Student s2(s1)  浅拷贝   深拷贝

浅拷贝 :只复制指向某个对象的指针,而不复制对象本身,相当于是新建了一个对象,该对象复制了原对象的指针,新旧对象还是共用一个内存块
var obj1 ={
	 name:'张三',
	 age:8,
	 pal:['王五','王六','王七']
	}
	var obj3 = shallowCopy(obj1)
	function shallowCopy (src){
	 var newObj = {};
	 for(var prop in src ){
		 console.log(prop)
		 if(src.hasOwnProperty(prop)){
			 newObj[prop] = src[prop]
		 }
	 }
	 return newObj
	}
	 obj3.name = '李四'
	 obj3.pal[0] = '王麻子'

	console.log("obj1", obj1); //{age: 8, name: "张三", pal: ['王麻子', '王六', '王七']}
	console.log("obj3", obj3); //{age: 8, name: "李四", pal: ['王麻子', '王六', '王七']}


深拷贝:是新建一个一模一样的对象,该对象与原对象不共享内存,修改新对象也不会影响原对象
var arr = ['jack',25,{hobby:'tennise'}];
		let arr1 = JSON.parse(JSON.stringify(arr))
		arr1[2].hobby='rose'
		arr1[0]='rose'
		console.log( arr[2].hobby) //tennise
		console.log( arr[0]) //jack


		var obj = {   //原数据,包含字符串、对象、函数、数组等不同的类型
	   name:"test",
	   main:{
		   a:1,
		   b:2
	   },
	   fn:function(){

	   },
		friends:[1,2,3,[22,33]]
   }

   function copy(obj){
		let newobj = null;   //声明一个变量用来储存拷贝之后的内容

	 //判断数据类型是否是复杂类型,如果是则调用自己,再次循环,如果不是,直接赋值即可,
	 //由于null不可以循环但类型又是object,所以这个需要对null进行判断
		if(typeof(obj) == 'object' && obj !== null){

	//声明一个变量用以储存拷贝出来的值,根据参数的具体数据类型声明不同的类型来储存
			newobj = obj instanceof Array? [] : {};

	//循环obj 中的每一项,如果里面还有复杂数据类型,则直接利用递归再次调用copy函数
			for(var i in obj){
				newobj[i] = copy(obj[i])
			}
		}else{
			newobj = obj
		}
		console.log('77',newobj)
	  return newobj;    //函数必须有返回值,否则结构为undefined
   }

	var obj2 = copy(obj)
	obj2.name = '修改成功'
	obj2.main.a = 100
   console.log(obj)
   console.log(obj2)




		// 安装lodash
		npm i --save lodash
		// 引入lodash
		var _ = require('lodash');
		var obj1 ={
			name:'jack',
			age:25,
		}
		let obj2 =_.cloneDeep(obj1)
		obj2.name = 'rose'
		console.log('obj1',obj1.name) //jack
		console.log('obj2',obj2.name) //rose


#include<iostream>
#include<vector>
#include<algorithm>
//用队列实现栈、用栈实现队列、给定序列判断合法出栈顺序(可随出随入)
         
//1.把待判断序列放进队列  2.把队列中的第一个元素与入栈序列的第一个元素一一比较,相等出栈,不相等继续将入栈序列入栈。若最终所有元素全部出栈,是合法顺序
//n入栈元素个数 qq是待判断队列 ss是判断栈
#include<stack>
#include<queue>
void judgeOrder(int*arr,int n,){
    queue<int>qq;
    stack<int>ss;
for(int i=0;i<n;i++)qq.push(arr[i]);
for(int i=1;i<=n;i++){
    while(!ss.empty()&&ss.top()==qq.front){
        qq.pop();
        ss.pop();
    }
     ss.push();   
}
if(ss.push)cout<<"Correct Order!"<<	endl;
else cout<<"Wrong Order!"<<endl;
}
void main(){
    int arr[]={3,4,2,1,5};
    int n=sizeof(arr)/sizeof(arr[0]);
    judgeorder(arr,n);
}
```

##### 
#include<stack>
#include<queue>
#include<deque>
#include<list>//带头结点的双向循环链表

using namespace std;

#if 0

//关联容器  已序群集 set map
//vector对象有字符串成员调用构造时须调用拷贝构造


void main() {
	vector<string > v;
	vector<vector<string>>vv;
	for (int i = 0; i < 3; i++) {
		v.push_back("");
		v[i].append(5, '*');
	}
	for (int j = 0;j < 3;j++) cout << v[j] << endl;
	cout << endl;
	cout << endl;

	for (int i = 0; i < 3; i++) {
		vv.push_back(vector<string>());
		for (int j = 0;j < 4;j++) {
			vv[i].push_back("12345");
			cout << vv[i][j] << endl;
		}
		cout << endl;
	}


	vector<int>v2;
	vector<int>::iterator iter;//迭代器定义
	for (iter = v2.begin();iter != v2.end();iter++) {
		cout << *iter << endl;
	}
	

	vector<int>v3;
	v3.reserve(10);//--v.capacity最小容量,利用push_back可以扩容
	v3.resize(5);//--v.size


}
#endif



#if 0
void main() {
	vector<vector<int>>vv;
	for (int i = 0; i < 3; i++) {
		vv.push_back(vector<int>());
		for (int j = 0;j < 4;j++) {
			vv[i].push_back(4);
		}
	}
	for (int i = 0; i < 3; i++) {
		
		for (int j = 0;j < 4;j++) {
			cout << vv[i][j];
		}
		cout << endl;
	}
}
#endif



#if 0
int Print(int n) {
	cout << n;
	return n;
}
void main() {
	vector<int> vv;
	copy(istream_iterator<int>(cin), istream_iterator<int>(), back_insert_iterator<vector<int>>(vv));
	sort(vv.begin(), vv.end());
    copy(vv.begin(), vv.end(), ostream_iterator<int>(cout," "));
	for_each(vv.begin(), vv.end(), Print(4));
	cout << endl;
} 
#endif
#if 0
template <class T>//类型种类有几个写几个class Tn
T Max(T a, T b)//函数模板
{
	return a > b ? a : b;
}
void main() 
{
	cout << Max(1, 2) << endl;
	cout << Max('a', 'b') << endl;//模板函数

}
#endif

#if 0
template <class T>
class A 
{
public:
	A(T i=0):m_i(i){}
	void print() {cout << i << endl;}
	private:
		int m_i = 0;
};
int main() {
	A<int> a(10);
	a.print();
}
#endif
设计一个求最小值栈

getmin操作复杂度为O(1)。有push,pop,top。

class Stack{
    public:
    void Push(int x){
        data.push(x);
        if(MinStack.empty())MinStack.push(x);
        else{
            if(x>MinStack.top())x=MinStack.top();
            MinStack.push(x);
        }
        
}
void Pop(){
    data.pop();
    MinStack.pop();
}
void Top();
void GetMin(){
    return MinStack.pop;
}
private:
stack<int>data;
stack<int>MinStack;};
带权路径长度相同的路径
class Node{};
Class Tree{};
void findpath(Node*&node, vector<vector<int>> &result,vector<int>&path,int sum,){
    if(!node)return;
    s=s+node->m_value;
    path.push_back(node->m_value);
    if(!node->m_left&&!node->m_right&&s==sum)result.push_back(path);
    fn(node->m_left,s,path,sum);
    fn(node->m_right,s,path,sum);
}
void main(){
    vector<int>path;
    vector<vector<int>> result;
    int s=0;
    int sum=14;
    Tree t;
}
智能指针

唯一性指针:操作堆区 my_unique_ptr

柔性数组:CDTree 两个类对象共用类的指针

移动实现:move

完美转发:forward

//柔性数组 类的最后一个成员是长度为0的数组
class  
线程池
多线程
int i=0;
const int n=100;
std::mutex mtx;
std::condition_variable mcv;
void funa(){
    std::unique_lock<std::mutex> lock(mtx);
    while(i%3!=0){
        mcv.wait();
    }
   if(i<=n) {
       cout<<"funa"<<i<<endl;
	   i++;
   }
} 
void funb(){
    std::unique_lock<std::mutex> lock(mtx);
    while(i%3!=1){
        mcv.wait();
    }
   if(i<=n) {
       cout<<"funb"<<i<<endl;
	   i++;
   }

} 
void func(){
    std::unique_lock<std::mutex> lock(mtx);
    while(i%3!=2){
        mcv.wait();
    }
   if(i<=n) {
       cout<<"func"<<i<<endl;
	   i++;
   }
} 
哲学家就餐

对象池的实现

频繁的系统调用(分配内存,创建进程或线程)导致程序频繁地从用户态转换到内核态,非常耗时,为提升程序性能,使用池化技术。

池化技术:提前保存大量资源,来备用资源或重复使用资源,内存池,(Socket/)线程池,连接池,对象池,

池化技术核心:用一个容器保存各种需要的对象,对连接/线程复用,控制复用数量和时间.

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张学灿@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值