Não há algum problema sério em aprender C++? Uma versão um pouco louca e gramaticalmente confusa da nota e um título um pouco longo e sem palavras fazem as pessoas questionarem o estado mental de Neo.

1. Sintaxe básica de C++

conversão de tipo

Nunca misture tipos não assinados e assinados.Quando
ambos são incluídos em uma expressão, o tipo assinado será convertido para o tipo não assinado e resultados inesperados ocorrerão quando o valor for negativo;

unsigned a = 1; int b = -1; cout<<a*b;//输出 4294967295
//详解: b的源码:100...1 负数转补码按位取反加1后为:1111...0  无符号类型把该值读出为4294967295 (结果视所在机器位数而定)

Ao usar tipos não assinados para loops, preste atenção ao fato de que eles nunca serão menores que 0.

Sequências de escape e tipos especificados

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Nota: "\1234" Os 3 primeiros constituem o valor octal correspondente ao valor do peitoril da sequência de escape

Insira a descrição da imagem aqui
Nota: Use L em vez de l minúsculo ao representar o tipo inteiro longo. É facilmente confundido com 1;

O sufixo existe para indicar claramente o tipo de dados do valor literal, evitando assim a conversão implícita de tipo ou ambiguidade por parte do compilador. No entanto, nem todos os tipos de dados requerem um sufixo, uma vez que o seu tipo pode ser inferido automaticamente a partir da forma do literal. Além disso, usar o sufixo errado pode levar a erros de compilação ou de tempo de execução, portanto, deve ser usado com cuidado. Sem palavras;

Insira a descrição da imagem aqui

(a) 字符  宽字符型字符(wchar_t类型)  字符串  宽字符型字符串
(b) 整数  无符号数  长整数  无符号长整数  八进制数  十六进制数
(c) 浮点型   单精度浮点型   long double类型的扩展精度浮点型 
(d) 整数  无符号整数 浮点数  科学计数法表示的浮点数

A inicialização da variável não é igual à atribuição (a inicialização consiste em criar uma variável e atribuir um valor inicial, a atribuição consiste em apagar o valor atual e substituí-lo por um novo valor). A declaração da variável especifica o tipo e o nome da variável
. Além do definição , também se aplica ao espaço de armazenamento e também pode atribuir valor inicial. (Recomenda-se inicializar cada variável do tipo integrado)

extern int i; //声明 i 
int j;//声明并定义 j
extern int k = 3; //赋初始值抵消了extern的作用变成了定义,且如果是在函数内部初始化extern标记的变量会报错

Uma variável deve e só pode ser definida uma vez em um arquivo. A variável usada em outros arquivos deve ser declarada, mas não deve ser definida repetidamente! (Uma variável pode e só pode ser definida uma vez, mas pode ser declarada várias vezes)

A convenção de nomenclatura para identificadores
consiste em letras, números e sublinhados e deve começar com uma letra ou sublinhado.
Não foi possível especificar o identificador

  • Algumas palavras-chave usadas na linguagem C++, como if, int, false, etc.
  • Algumas palavras reservadas na biblioteca padrão C++ não podem ser sublinhadas duas vezes seguidas ou sublinhadas começando com letra maiúscula.
  • Os identificadores definidos fora de uma função não podem começar com um sublinhado.

Especificações de identificador recomendadas

  • Saiba o significado depois de ver o nome, pode refletir o significado real e ser fácil de entender
  • Letras minúsculas em nomes de variáveis, como índice
  • O nome da classe começa com uma letra maiúscula, como Índice
  • Identificadores que consistem em diversas letras devem ser separados por sublinhados ou começar com uma letra maiúscula, como student_loan_up ou studentLoanUp.

Escopo
O escopo global e
o escopo do bloco são aninhados. O escopo externo declara um nome, e seu escopo aninhado, ou seja, o escopo interno, pode acessar o nome, e o escopo interno pode redefinir o escopo externo. O domínio já possui um nome.

Principais diferenças entre referências e ponteiros

  1. As referências devem ser inicializadas quando são criadas (os ponteiros podem ser inicializados a qualquer momento).
  2. Não pode haver referências NULL e as referências devem estar associadas a locais de armazenamento legais (os ponteiros podem ser NULL).
  3. Depois que uma referência é inicializada, o relacionamento de referência não pode ser alterado (um ponteiro pode alterar o objeto ao qual se refere a qualquer momento).

https://www.runoob.com/w3cnote/cpp-difference-between-pointers-and-references.html

O uso de ponteiros não inicializados pode facilmente levar a erros, por isso não se sabe se ele é inicializado como nullptr ao apontar para um objeto específico, como: int *p = nullptr; portanto, para determinar se um ponteiro aponta para um endereço válido,
basta determine se é nullptr ou se não foi inicializado. Para ponteiros, você pode tentar... capturar se há um erro.

void* é um tipo de ponteiro especial que pode armazenar o endereço de qualquer objeto.

O problema com int* p e int *p é que p, cujo tipo básico é int, é um ponteiro para int, portanto é recomendado usar o segundo método de escrita, int *p1, *p2;

Um ponteiro para um ponteiro precisa ser desreferenciado duas vezes para acessar o objeto original;
uma referência a um ponteiro, a referência em si não é um objeto, então um ponteiro para uma referência não pode ser definido, mas o ponteiro é um objeto, então não há é uma referência ao ponteiro;

int i = 33;
int *p;//int 类型的指针p
int *&r = p;//从右往左看,r 是 对指针p的引用
r = &i;//r是指向p的引用,给r赋值&i 就是让p指向i
*r = 0;//解引用 r 得到 i,也就是p指向的对象,改i的值为0

Quando confrontado com ponteiros complexos ou declarações de referência, ler da direita para a esquerda pode ajudar a esclarecer o verdadeiro significado;

A maneira de definir uma variável const e declará-la em vários arquivos é adicionar a palavra-chave extern, seja ela definida ou declarada;

extern const int bufsize = fcn();//1.cc定义并初始化一个常量,并让该常量能被其他文件访问

** Const de nível inferior e const de nível superior? **

Expressão constante: uma expressão cujo valor não será alterado e o resultado do cálculo pode ser obtido durante a compilação.
Por exemplo, const staff_size = get_size(); não é, porque não pode ser obtido até o tempo de execução. Const int limit = 20; é uma constante expressão.

C++11: Se você determinar que uma variável é uma expressão constante, declare-a como um tipo constexpr;

Derivação automática de tipo
1. Ao usar uma referência como valor inicial, use o tipo do objeto de referência como o tipo de auto;
int i = 0, &r = i;
auto a = r; //um tipo é int
2. auto irá ignorar o const de nível superior, Manter o const subjacente;
auto &h = 42; //A referência não-const precisa ser vinculada a um objeto modificável;
const auto &j = 42;

Tudo deve ser o mais simples possível, mas não mais simples

Classe é o nome abstrato e coletivo de objetos, e objetos são instâncias de classes;

Cópia superficial: copia apenas o endereço do ponteiro, o construtor de cópia padrão C++
e a sobrecarga do operador de atribuição são cópias superficiais;
economiza espaço, mas causa facilmente vários lançamentos;
cópia profunda: realoca a memória heap e copia
o conteúdo apontado pelo ponteiro.
Desperdiça espaço, mas não resulta em múltiplas liberações;

copiar ao escrever

2. Ponteiros C++

Ponteiros não inicializados e ilegais, você deve ter muito cuidado ao usar ponteiro indireto para garantir que eles sejam inicializados e atribuídos corretamente!
1. Se você não sabe para onde ele aponta inicialmente ou quando não é usado, você pode inicializá-lo como nulo.
2. Antes de fazer uma referência indireta a um ponteiro, determine se o valor do ponteiro é nulo;

int *a;//未初始化化
*a = 12//非法访问

Se você tiver sorte, você localiza um endereço ilegal e o programa termina com um erro. Se você não tiver sorte, você localiza um endereço acessível e o modifica. O erro é difícil de detectar e o erro causado pode ser completamente inesperado!

Lvalue e rvalue
Insira a descrição da imagem aqui
O lado esquerdo do sinal = é lvalue e o lado direito do sinal = é rvalue. O valor da esquerda ocupa o espaço de memória em cp+1 conforme mostrado acima, e o valor da direita ocupa o valor do espaço de memória;

char ch = 'a';
char *cp = &ch;

Em relação a ++++, ---- e outros operadores:
A forma como o programa compilador é decomposto em símbolos é: leia caractere por caractere.
Se o caractere puder formar um símbolo, então leia o próximo caractere até que os caracteres inseridos
não sejam lidos. não formam mais um símbolo significativo. Este processo é denominado "método ganancioso".
Por exemplo: int a=1,b=2;c;
c=a+++b;/∥ é equivalente a a+++b
d=a++++b;/∥ é equivalente a af+++ b, erro

Insira a descrição da imagem aqui
Armazenamento de código e dados em programas C++;

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

RAlI (Resource Acquisition Is Initialization) :
Um método de gerenciamento de recursos exclusivo do C++. Algumas outras linguagens, como Rust, também adotaram RAII, mas entre as principais linguagens de programação, C++ é a única que depende de RAII para gerenciamento de recursos. RAli depende de pilhas e destruidores para gerenciar todos os recursos, incluindo memória heap.
O uso de RAll permite que C++ gerencie efetivamente a memória sem exigir um método de coleta de lixo semelhante ao Java. A existência de RAll também é a principal razão pela qual, embora a coleta de lixo possa teoricamente ser usada em C++, ela nunca se tornou realmente popular.
RAll tem alguns representantes de ponteiros inteligentes relativamente maduros: como std:auto_ptr e boost:shared_ptr

Insira a descrição da imagem aqui

Problema de vazamento de memória (vazamento de memória)
O que é um problema de vazamento de memória:
refere-se à memória heap alocada dinamicamente no programa que não é liberada ou não pode ser liberada por algum motivo,
resultando em desperdício de memória do sistema, fazendo com que o programa fique lento inativo ou até mesmo falha do sistema como resultado de.
Causas e métodos de solução de vazamentos de memória:
1. Os vazamentos de memória ocorrem principalmente no método de alocação de memória heap, ou seja, "após a configuração da memória, todos os ponteiros que apontam
para a memória são perdidos". Sem um mecanismo de coleta de lixo como a linguagem, essas
fatias de memória não podem ser devolvidas ao sistema.
2. Como os vazamentos de memória são problemas durante a execução do programa e não podem ser identificados através da compilação, eles
só podem ser identificados e diagnosticados durante a execução do programa.

Quatro ponteiros inteligentes comumente usados ​​​​são introduzidos em C++:
unique_ptr, shared_ptr, fraco_ptr;
auto_ptr: obsoleto em C++ 11 e excluído oficialmente em C++ 17;

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Problemas de uso
Insira a descrição da imagem aqui
Problemas de propriedade
Insira a descrição da imagem aqui
Referências circulares: A contagem de referências traz problemas de referência circular, fazendo com que a memória heap não possa ser reciclada normalmente, causando vazamentos de memória.

Insira a descrição da imagem aqui

Referência C++
Insira a descrição da imagem aqui

Para tipos básicos em funções, a passagem por valor é mais eficiente, e para tipos personalizados, a passagem por referência a const é mais eficiente;

Elimine ponteiros "selvagens"
Ponteiros apontando para memória "lixo". If e outros julgamentos não funcionam para eles porque NULL não está definido;
geralmente há três situações:
1. Variáveis ​​de ponteiro não são inicializadas;
2. Ponteiros que foram liberados e não utilizados não são definidos como NULL, como ponteiros após exclusão e livre;
3. As operações do ponteiro excedem o escopo da variável;

Notas sobre o uso de ponteiros: Defina o valor como NULL para
ponteiros não inicializados, não utilizados ou fora do intervalo . (É difícil, os ponteiros são usados ​​em vários lugares e é difícil determinar quando eles não são mais necessários. Solução: ponteiros inteligentes)

O ponteiro nulo é um ponteiro para nulo e é usado para variáveis ​​​​de ponteiro de inicialização de memória. O número de memória 0 ~ 255 é a memória ocupada pelo sistema e é inacessível; o ponteiro selvagem é um ponteiro que aponta
para um espaço de memória ilegal. Ambos os acessos devem relatar um erro, mas executar em Dev é o seguinte Código: Ele compila corretamente e ainda pode ser executado, mas não há saída. A janela fecha automaticamente após a execução por um período de tempo. Por que isso?

#include <bits/stdc++.h>

using namespace std;

int main(){
    
    
	int a = 10;
	int *p = NULL;
	cout << *p <<endl;
	
	int *q = (int *)0x1110;
	cout << *q <<endl;
	return 0;
}

Embora a sintaxe esteja correta e possa passar pelo compilador, devido a violações de acesso à memória causadas pela desreferenciação de ponteiros nulos e ponteiros selvagens, o sistema operacional encerra a execução do programa para proteger o sistema.

Insira a descrição da imagem aqui
O método de armazenamento real da máquina: os números positivos são armazenados diretamente e os números negativos retêm o bit de sinal e invertem o +1 bit a bit;
big endian é comumente usado na Internet e está em conformidade com os hábitos de leitura humanos, e little endian é usado pela maioria PCs pessoais e em conformidade com a máquina;

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Isto é muito importante e deve ser observado! ! !
Insira a descrição da imagem aqui
A estrutura sdshdr projetada no Redis possui uma variável len para armazenar o comprimento da string, que não precisa ser percorrida para calcular; existe um espaço livre para gerenciar a capacidade restante. Se a capacidade não for suficiente, ele irá expandir e modificar automaticamente o tamanho da lente;

ponteiros e referências

Insira a descrição da imagem aqui

Matriz de ponteiros, cada um nesta matriz é um ponteiro. T *t[ ]
ponteiro de array (um ponteiro para um array), este ponteiro aponta para um array. T (*t) [ ]

Insira a descrição da imagem aqui
No terceiro exemplo, primeiro observe o caractere esquerdo da primeira modificação const, o que significa que o valor do ponteiro não pode ser alterado, e depois observe a segunda modificação const de *, o que significa que o ponteiro do ponteiro não pode ser alterado;

Existem três situações em que ponteiros const modificados

  1. ponteiro modificado const - ponteiro constante (o ponteiro apontado pode ser alterado, mas o valor apontado não pode ser alterado)
  2. constante modificada const - constante do ponteiro (o ponteiro não pode ser alterado, o valor do ponteiro pode ser alterado)
  3. const modifica ponteiros e constantes (nenhum deles pode ser alterado)

Veja se o lado direito de const é um ponteiro ou uma constante. Se for um ponteiro, é um ponteiro constante. Se for uma constante, é uma constante de ponteiro.

const é frequentemente usado para evitar uso indevido

ponteiro inteligente

A memória na área de heap deve ser liberada manualmente, caso contrário ocorrerão vazamentos de memória;

Solução: Ponteiros inteligentes são modelos de classe. Crie um objeto de ponteiro inteligente na pilha, entregue o ponteiro comum ao objeto de ponteiro inteligente e, quando o objeto de ponteiro inteligente expirar, chame o destruidor para liberar a memória do ponteiro comum.

unique_ptr: o objeto apontado exclusivamente para
shared_ptr:
wear_ptr:

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

3. Biblioteca C++STL

A relação entre os seis componentes principais da biblioteca stl
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

recipiente

Os contêineres são usados ​​para armazenar dados;
os contêineres STL são divididos em duas categorias: Contêineres
de sequência :
os elementos neles são todos classificáveis ​​(ordenados). STL fornece contêineres de vetor, lista, deque e outros contêineres de sequência, enquanto pilha, fila, fila de prioridade é o contêiner adaptador; Containers
Associativos
: Cada elemento de dados é composto por uma chave (key) e um valor (Value). Quando o elemento é inserido no container, pressione sua tecla de alguma forma. Regras específicas são colocadas no local apropriado; STL comum contêineres associados, como: set, multiset, map, multimap;

#include <bits/stdc++.h>

using namespace std;

struct Display{
    
    
	void operator()(int i){
    
    
		cout << i << " ";
	}
};

int main(){
    
    
	int arr[4] = {
    
     1, 2, 3, 4};
	vector<int> vec(arr, arr+4);//动态数组 
	list<int> lis(arr, arr+4);//链表 
	deque<int> deq(arr, arr+4);//双端队列
	queue<int> que(deq);//队列 
	stack<int> sta(deq);//栈 
	priority_queue<int> prique(arr, arr+4);//优先队列 
	
	for_each(vec.begin(), vec.end(), Display());
	for_each(deq.begin(), deq.end(), [](int i){
    
    
		cout<< i << " ";
	});
	
	while(!que.empty()){
    
    
		cout << que.front() << " ";
		que.pop();
	}
	while(!sta.empty()){
    
    
		cout << sta.top() << " ";
		sta.pop();
	}

	cout<<endl;
	map<string, int> studentlevel;
	studentlevel["level1"] = 1;
	studentlevel["..."] = 3;
	studentlevel["level6"] = 6;
	studentlevel.insert(pair<string, int>("level4", 4));
	for_each(studentlevel.begin(), studentlevel.end(), [](pair<string, int> i){
    
    
		cout<<i.first<<":"<<i.second<<endl; 
	});
	
	map<string, int>::iterator iter = studentlevel.find("level6");
	if(iter != studentlevel.end()){
    
    
		cout<<"level6 超能力者人数:"<<iter->second<<endl; 
	}
	
	return 0;
}

**Muito importante observar: **Cuidado com problemas de falha do iterador, como iter = studentlevel.earse(''cc''); exclua o valor com a chave cc e retorne o iterador na próxima posição; (*it)
. vazio(); simplificou->empty();

Para qualquer corpo de loop que use um iterador, não adicione elementos ao contêiner ao qual o iterador pertence;
por exemplo, push_back pode fazer com que o iterador do objeto vetorial se torne inválido;
por exemplo, um loop for de intervalo adiciona elementos ao vetor .

functor

  • Functors geralmente não são usados ​​sozinhos, principalmente para uso com algoritmos STL.
  • Os ponteiros de função não podem atender aos requisitos de abstração do STL, não podem atender aos requisitos dos blocos de construção de software e não podem ser combinados com outros componentes do STL;
  • A essência é que a classe sobrecarrega um operador() e cria um objeto que se comporta como uma função.

Do ponteiro de função->genérico->functor->modelo functor; preguiçoso

bool MySort(int a, int b){
    
    
	return a ‹ b;
}

void Display(int a){
    
    
	cout << a <<" ";
}

int main(){
    
    
	//C++方式
	int arr[] = {
    
    4,3, 2, 1,7};
	sort(arr, arr + 5, MySort);
	for_each(arr, arr + 5, Display);

}

Se o tipo de dados mudar, muitas funções precisarão ser sobrecarregadas, o que é muito problemático, então surgiram os genéricos

template<class T>
bool MySort(T const& a, T const& b){
    
    
	return a ‹ b;
}

template<class T>
void Display(T const& a){
    
    
	cout << a <<" ";
}

int main(){
    
    
	//C++泛型
	int arr[] = {
    
    4,3, 2, 1,7};
	sort(arr, arr + 5, MySort<int>);
	for_each(arr, arr + 5, Display<int>);
}

Depois há o funtor


struct mySort{
    
    
	bool operator()(int a, int b){
    
    
		return a ‹ b;
	}
}

struct Display{
    
    
	void Display(int a){
    
    
		cout << a <<" ";
	}
}

int main(){
    
    
	//C++仿函数
	int arr[] = {
    
    4,3, 2, 1,7};
	sort(arr, arr + 5, mySort());
	for_each(arr, arr + 5, Display());
}

O próximo é o modelo functor, o tipo básico não precisa ser adicionado, mas pode ser adicionado se o consumo do objeto for relativamente grande.

template<class T>
struct mySort{
    
    
	bool operator()(T const&  a, T const&  b){
    
    
		return a ‹ b;
	}
}

template<class T>
struct Display{
    
    
	void Display(T const&  a){
    
    
		cout << a <<" ";
	}
}

int main(){
    
    
	//C++仿函数
	int arr[] = {
    
    4,3, 2, 1,7};
	sort(arr, arr + 5, mySort<int>();
	for_each(arr, arr + 5, Display<int>();
}

Algoritmo

Algoritmos em STL são divididos aproximadamente em quatro categorias: incluídos em,,
1. Algoritmos de sequência não variável: refere-se a algoritmos que não modificam diretamente o conteúdo dos contêineres que operam;
2. Algoritmos de sequência variável: refere-se àqueles que podem modificar o conteúdo dos contêineres que eles operam. Algoritmos;
3. Algoritmos de classificação: incluindo algoritmos para classificar e mesclar sequências, algoritmos de pesquisa e operações de conjunto em sequências ordenadas;
4. Algoritmos numéricos: realizar cálculos numéricos no conteúdo do contêiner;
os algoritmos mais comuns incluem :
algoritmos de pesquisa, classificação e gerais, algoritmos de permutação e combinação, algoritmos numéricos, algoritmos de conjunto e outros algoritmos

transform(); função de cálculo de contêiner; função estatística de contagem; binary_search(); pesquisa binária;

int main(){
    
    
	int arr[] = {
    
    1, 1, 1, 2, 2, 3, 4, 5, 5, 6};//父序列 
	vector<int> zi(arr+2, arr+6); //子序列 
	int len = sizeof(arr)/sizeof(arr[0]);
	cout << count(arr, arr+len, 1) << endl; 
	cout << count_if(arr, arr+len, bind2nd(less<int>(), 4)) << endl; 
	cout << binary_search(arr, arr + len, 6)<<endl;
	cout<< *search(arr, arr+len, zi.begin(), zi.end()) << endl;
	return 0;
}

Implementação de arranjo completo de caligrafia

Insira uma string completa sem caracteres repetidos e imprima a disposição completa dos caracteres na string
. Por exemplo, insira 123 = 3 2 1 = 3!
Produza a situação total
123
132
213
231
312
321

#include <bits/stdc++.h>
//f(123)=1+f(23),f(23)=2+f(3),f(3)=3递归
using namespace std;

void swap(char*a, char *b){
    
    
	char tmp = *a;
	*a = *b;
	*b = tmp;
}

void permutation(char *ptr, char* postion){
    
    
	if(*postion == '\0'){
    
    //基准点,退出
		cout << ptr <<endl;
	}
	for (char* pChar = postion; *pChar != '\0'; pChar++){
    
    
		swap(*pChar, *postion);//依次和后面的字符交换,比如123,定1位,依次交换2,3
		permutation(ptr, postion + 1);//递归下去
		swap(*postion, *pChar);//别忘了换回来
	}
}

int main(){
    
    
	char test[] = "321";
	permutation(test, test);
	return 0;
}

A ordem da matriz deve ser garantida. Por exemplo, next é de pequeno para grande. Se você implementá-lo sozinho, não perderá o arranjo. Prev está na ordem de grande para pequeno. O arranjo completo funciona next_permutation() e
prev_permutation () em stl;

sort
O algoritmo de classificação do STL
usa QuickSort (classificação rápida) quando a quantidade de dados é grande e mescla e classifica por segmentos.
Uma vez que a quantidade de dados segmentados é inferior a um determinado limite (16), para evitar carga extra excessiva causada pela chamada recursiva de QuickSort, InsertSort (classificação por inserção) é usado em seu lugar.
Se o nível de recursão for muito profundo, HeapSort (heap sort) será usado.

iterador

Semelhante aos ponteiros inteligentes, um pequeno caso gc manuscrito usa o método iterador;

Código-fonte aberto MyGC
Insira a descrição da imagem aqui

Int main0
GCPtr<int> p;
try{
    
    
p = new int;
catch (bad_alloc exc)X
cout << "Allocation failure!\n";
return 1;
3
*p =88;
*p+=1;
cout << "Value at p is:* << *p << endl;
GCPtr<int> p1 =p;
cout << "p's list size;: " << p.gclistSize() << endl;
p.showlist(0;
GCPtr<int, 10> pA = new int[10];
Iter<int> it = pA.beginO;
int index = 1;
for ( it != pA.end); it++)
7it = index++;

Insira a descrição da imagem aqui
O ponteiro que aponta para o objeto contém uma contagem de referência de referência, mas usa uma lista para registrar o ponteiro e libera todos os ponteiros da lista no final para resolver o problema de referência circular.
Insira a descrição da imagem aqui

adaptador de recipiente

pilha pilha:
um contêiner "primeiro a entrar, primeiro a sair", a estrutura de dados subjacente é deque;
fila fila:
um contêiner "primeiro a entrar, primeiro a sair", a estrutura de dados subjacente é deque;
prioridade_queue fila de prioridade:
uma fila especial, que pode ser classificada na fila (heap sort), a estrutura de implementação subjacente é vetorial ou deque;

Fila de prioridade

priority_queue<int> a;//默认大根堆,升序排列
priority_queue<int, vector<int>, greater<int>> b;//升序排列大根堆
priority_queue<int, vector<int>, less<int>> c;//降序排列小根堆

greater和less是仿函数,就是一个类中重载operator()的实现,类就有了类似函数的行为即仿函数,当涉及自定义类型当然可以自己重载;

struct cmp{
    
    
	bool operator(type a, type b){
    
    
		return a.x < b.x;//大顶堆
	}
}

alocador de espaço

  • "STL Source Code Analysis" Hou Jie, versão SGI STL é mais legível;
  • Do ponto de vista do uso, o alocador funciona silenciosamente oculto em outros componentes e não precisa de cuidados, porém, do ponto de vista da compreensão da implementação do STL, é o componente que precisa ser analisado primeiro;
  • A análise do alocador pode refletir as ideias de otimização do C++ no desempenho e gerenciamento de recursos;

Resumo STL
Os seis componentes principais do STL trazem novo polimorfismo e reutilização para a programação de software e são a essência da eficiência da linguagem C++ moderna; o
caminho de aprendizagem de genéricos e STL é muito íngreme e é recomendado que os iniciantes aprendam primeiro o uso básico e simples extensões;
Depois de dominar uma determinada base, você pode melhorar suas capacidades estudando e analisando mais o código-fonte e escrevendo seus próprios componentes;

Outras bibliotecas

biblioteca boost Biblioteca
Boost é o nome geral de algumas bibliotecas C++ que fornecem extensões para a biblioteca padrão da linguagem C++. Ela é desenvolvida e mantida pela organização da comunidade Boost. A biblioteca Boost pode funcionar perfeitamente com a biblioteca padrão C++ e fornecer funções estendidas para ela ; a biblioteca padrão C++ também absorve gradualmente algumas de suas funções;
Boost pode ser dividido em mais de 20 categorias: bibliotecas de processamento de strings e texto, bibliotecas de contêineres, bibliotecas de algoritmos, objetos de função e bibliotecas de programação de alta ordem, bibliotecas de classes abrangentes, etc. .;
site oficial: https://www.boost.org/
Espelho: https://dl.bintray.com/boostorg/release/

Estrutura de aplicativo HTTP Drogon baseada em C++ 14/17 (o nome de um dragão (Drogon) em "Game of Thrones"): https://github.com/drogonframework/drogon/blob/master/README.zh- CN .md

Documento chinês traduzido por grpc: https://doc.oschina.net/grpc?t=58008 (estrutura RPC de plataforma cruzada), explicação: https://juejin.cn/post/7047885453336248327

Estrutura rpc de código aberto da Tencent phxrpc: https://gitee.com/mirrors/PhxRPC# https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2FTencent%2Fphxrpc%2Fwiki
https:// github.com/Tencent/phxrpc

4. Padrões de design C++

Existem 23 padrões de design reutilizáveis ​​e orientados a objetos comuns em software que fornecem soluções gerais para alguns problemas comuns com base em experiências anteriores.
Os padrões de design também têm custos e cenários aplicáveis, mas não são onipotentes.Esses 23 tipos são realmente adequados para cenários com forte escalabilidade e serão usados ​​repetidamente em um grande número de cenários com algumas mudanças no futuro;

Padrão singleton

Insira a descrição da imagem aqui

Padrão de observador

Insira a descrição da imagem aqui
Ideias de implementação:
dissociar as responsabilidades do problema, abstrair observável e observador, e distinguir abstração e entidade;

class Observer
public:
	Observer();
	virtual ~Observer();
	//当被观察对象发生变化时,通知被观察者调用这个方法
	virtual void Update(void* pArg) = 0;
}

class User1:public Observer{
    
    
	virtual void Update(void* pArg)
	cout <<"User1 Got News:" << endl;
}

class User2 :public Observer{
    
    
	virtual void Update(void* pArg)
	cout <<"User2 Got News:" << endl;
}

O que são void, NULL e nullptr?
void* é um tipo de ponteiro geral que pode apontar para qualquer tipo de dados. Ele não está diretamente relacionado a um tipo de dados específico, portanto não pode ser desreferenciado e requer conversão de tipo explícita para ser usado. Por exemplo:

void* ptr = nullptr; // ptr é um ponteiro nulo
int* intPtr = static_cast<int*>(ptr); // Converte o ponteiro void em ponteiro int
Nas versões mais antigas do C++, NULL era definido como o inteiro 0. Isso significa que pode ser usado como um ponteiro para o valor nulo. No entanto, usar o número inteiro 0 pode levar a alguma ambigüidade, pois 0 também pode ser um valor de outros tipos de números inteiros. No C++ moderno, é recomendado usar nullptr em vez de NULL. Por exemplo:

int* ptr = nullptr; // ptr é um ponteiro nulo
nullptr é uma palavra-chave introduzida em C++ 11 para representar um ponteiro nulo. nullptr tem melhor segurança de tipo em comparação com NULL. É implicitamente conversível em qualquer tipo de ponteiro e não pode ser confundido com outros tipos inteiros. Por exemplo:

int* ptr = nullptr; // ptr é um ponteiro nulo

Um ponteiro é uma variável usada para armazenar um endereço de memória, e os dados apontados podem ser acessados ​​através do operador de desreferência *. Um ponteiro nulo significa que o ponteiro não aponta para nenhum endereço de memória válido. Em C++, esses conceitos podem ser usados ​​para lidar convenientemente com a situação em que o ponteiro é nulo e evitar erros ou comportamentos indefinidos.

Insira a descrição da imagem aqui
Os 23 padrões de design orientados a objetos são classificados em padrões criativos, estruturais e comportamentais; os
padrões de design não são onipotentes, eles são baseados em pontos de mudança do sistema e podem ser usados ​​onde quer que haja mudanças; os
padrões de design estão se dissociando e, para expandir, geralmente é evoluído e precisa de evolução para ser
posicionado com precisão;
o padrão de design é um método de design de software, não um padrão. Atualmente, a maioria das estruturas atuais já contém
um grande número de idéias de padrões de design;

Programação genérica

Insira a descrição da imagem aqui

Se a orientação a objetos é um método de chamar funções através de uma camada indireta em troca de uma abstração, então a programação genérica é uma abstração mais direta, que não perde eficiência por causa da camada indireta; ao contrário do polimorfismo dinâmico orientado a objetos, a programação genérica
é uma espécie de polimorfismo estático, que gera o código mais direto através do compilador em tempo de compilação;
a programação genérica pode separar algoritmos de tipos e estruturas específicas e reutilizar o código tanto quanto possível;

template<class T>
T max(T a, T b){
    
    
	return a > b ? a : b;
}

//特化
template<class T1, class T2>
int max(T1 a, T2 b){
    
    
	return static_cast<int>(a > b ? a : b);
}

int main(){
    
    
	cout << max(1, 3) << endl;
	cout << max(3.5, 1.5) << endl;
	cout << max('a', 'b') << endl;

	cout << max(10, 3.5) << endl;
}

O compilador instanciará uma instância de função de modelo correspondente com base nos tipos de parâmetros reais passados ​​para a função.

A relação entre genéricos, polimorfismo e sobrecarga: Os genéricos podem melhorar a reutilização do código, mas não envolvem diretamente os conceitos de polimorfismo ou sobrecarga. Polimorfismo refere-se ao recurso que permite que objetos de classes diferentes respondam à mesma mensagem, enquanto sobrecarga refere-se a permitir múltiplas funções com o mesmo nome, mas diferentes listas de parâmetros no mesmo escopo. Embora os genéricos possam melhorar a reutilização do código, eles não afetam diretamente esses conceitos.

Este exemplo demonstra genéricos. A função max não precisa alterar repetidamente os tipos. Em vez disso, o compilador gera chamadas de função com base nos parâmetros e modelos passados. No entanto, se a função genérica não atender às nossas necessidades, ela precisa ser especializada . Você pode interromper a depuração para ver qual função está em execução.

Uma vez cometido um erro na programação genérica, é difícil para os iniciantes corrigi-lo! Porque o compilador faz muitas coisas automaticamente;

programação funcional;

static_cast

Insira a descrição da imagem aqui

//C++ const转ẽ
const int a = 10;
//int* pA = &a;
int* pA = const_cast<int*>(&a);
*pA = 100:
cout<<a<<endl;可能任然是10,内存模型问题
return O;

Insira a descrição da imagem aqui

padrão de adaptador

Reutilize as funções do código original, não altere e depois crie novas funções.
Herança múltipla é muito ruim. Tem algo a ver com C++,
problemas de herança de diamante e herança virtual.

A primeira: usar herança múltipla.
A segunda: usar combinação para instanciar objetos da classe original como variáveis-membro da nova classe.

Acho que você gosta

Origin blog.csdn.net/BinBinCome/article/details/131736702
Recomendado
Clasificación