¿No existe algún problema grave al aprender C++? Una versión un poco loca y gramaticalmente confusa de la nota y un título un poco largo y sin palabras hacen que la gente cuestione el estado mental de Neo.

1. Sintaxis básica de C++

conversión de tipo

Nunca mezcle tipos con signo y sin signo
. Cuando ambos se incluyen en una expresión, el tipo con signo se convertirá al tipo sin signo y se producirán resultados inesperados cuando el valor sea negativo;

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

Cuando utilice bucles for sin signo, preste atención al hecho de que nunca serán menores que 0.

Secuencias de escape y tipos especificados.

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Nota: "\1234" Los primeros 3 constituyen el valor octal correspondiente al mínimo de la secuencia de escape.

Insertar descripción de la imagen aquí
Nota: Utilice L en lugar de l minúscula cuando represente un tipo de entero largo. Se confunde fácilmente con 1;

El sufijo existe para indicar claramente el tipo de datos del valor literal, evitando así la conversión de tipo implícita o la ambigüedad por parte del compilador. Sin embargo, no todos los tipos de datos requieren un sufijo ya que su tipo se puede inferir automáticamente de la forma del literal. Además, el uso de un sufijo incorrecto puede provocar errores de compilación o de tiempo de ejecución, por lo que debe utilizarse con cuidado. Sin habla;

Insertar descripción de la imagen aquí

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

La inicialización de variables no es igual a la asignación (la inicialización es crear una variable y asignar un valor inicial, la asignación es borrar el valor actual y reemplazarlo con un nuevo valor). La declaración de variable
especifica el tipo y nombre de la variable. Además, la La definición también se aplica al espacio de almacenamiento y también puede asignar un valor inicial. (Se recomienda inicializar cada variable del tipo incorporado)

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

Una variable debe y solo puede definirse una vez en un archivo. La variable utilizada en otros archivos debe declararse, ¡pero no debe definirse repetidamente! (Una variable puede y solo puede definirse una vez, pero puede declararse varias veces)

La convención de nomenclatura para identificadores
consta de letras, números y guiones bajos, y debe comenzar con una letra o un guión bajo.
No se puede especificar el identificador

  • Algunas palabras clave utilizadas en lenguaje C++, como if, int, false, etc.
  • Algunas palabras reservadas en la biblioteca estándar de C++ no se pueden subrayar dos veces seguidas ni subrayar comenzando con una letra mayúscula.
  • Los identificadores definidos fuera de una función no pueden comenzar con un guión bajo.

Especificaciones de identificador recomendadas

  • Conozca el significado después de ver el nombre, puede reflejar el significado real y ser fácil de entender.
  • Letras minúsculas en nombres de variables, como índice
  • El nombre de la clase comienza con una letra mayúscula, como Índice
  • Los identificadores que constan de varias letras deben estar separados por guiones bajos o comenzar con una letra mayúscula, como Student_loan_up o StudentLoanUp.

Ámbito
El alcance global y
el alcance del bloque están anidados. El alcance externo declara un nombre, y su alcance anidado, es decir, el alcance interno, puede acceder al nombre, y el alcance interno puede redefinir el alcance externo. El dominio ya tiene un nombre.

Diferencias clave entre referencias y sugerencias

  1. Las referencias deben inicializarse cuando se crean (los punteros se pueden inicializar en cualquier momento).
  2. No puede haber referencias NULL y las referencias deben estar asociadas con ubicaciones de almacenamiento legales (los punteros pueden ser NULL).
  3. Una vez que se inicializa una referencia, la relación de referencia no se puede cambiar (un puntero puede cambiar el objeto al que hace referencia en cualquier momento).

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

El uso de punteros no inicializados puede generar errores fácilmente, por lo que no se sabe si se inicializa en nullptr cuando apunta a un objeto específico, como por ejemplo: int *p = nullptr; por lo tanto, para determinar si un puntero apunta a una dirección legal,
simplemente determine si es nullptr o si no está inicializado Para los punteros, puede intentar... detectar si hay un error.

void* es un tipo de puntero especial que puede almacenar la dirección de cualquier objeto.

El problema con int* p e int *p es que p, cuyo tipo básico es int, es un puntero a int, por lo que se recomienda utilizar el segundo método de escritura, int *p1, *p2;

Es necesario desreferenciar un puntero a un puntero dos veces para poder acceder al objeto original;
una referencia a un puntero, la referencia en sí no es un objeto, por lo que no se puede definir un puntero a una referencia, pero el puntero es un objeto, por lo que no es una referencia al puntero;

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

Cuando se enfrenta a declaraciones complejas de indicadores o referencias, leer de derecha a izquierda puede ayudar a aclarar el verdadero significado;

La forma de definir una variable constante y declararla en varios archivos es agregar la palabra clave extern ya sea que esté definida o declarada;

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

** ¿Constancia de nivel inferior y constante de nivel superior? **

Expresión constante: una expresión cuyo valor no cambiará y el resultado del cálculo se puede obtener durante la compilación.
Por ejemplo, const staff_size = get_size(); no lo es, porque no se puede obtener hasta el tiempo de ejecución. Const int limit = 20; es una constante expresión.

C++ 11: si determina que una variable es una expresión constante, declarela como un tipo constexpr;

Derivación de tipo automático
1. Cuando use una referencia como valor inicial, use el tipo del objeto de referencia como el tipo de auto;
int i = 0, &r = i;
auto a = r; //un tipo es int
2. auto ignorará la constante de nivel superior y mantendrá la constante subyacente;
auto &h = 42; //La referencia no constante debe estar vinculada a un objeto modificable;
const auto &j = 42;

Todo debería hacerse lo más sencillo posible, pero no más sencillo.

Clase es el nombre abstracto y colectivo de objetos, y los objetos son instancias de clases;

Copia superficial: solo copia la dirección del puntero,
el constructor de copia predeterminado de C++ y la sobrecarga del operador de asignación son copias superficiales;
ahorra espacio, pero fácilmente provoca múltiples liberaciones;
copia profunda: reasigna la memoria del montón y copia
el contenido señalado por el puntero.
Desperdicia espacio pero no produce múltiples emisiones;

Copiar en escrito

2. Punteros de C++

Punteros no inicializados e ilegales, debe tener mucho cuidado al utilizar la dirección indirecta del puntero para asegurarse de que se inicialicen y asignen correctamente.
1. Si no sabe a dónde apunta al principio o cuándo no se utiliza, puede inicializarlo a nulo
2. Antes de hacer una referencia indirecta a un puntero, determine si el valor del puntero es nulo;

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

Si tiene suerte, localiza una dirección ilegal y el programa finaliza con un error. Si no tiene suerte, localiza una dirección accesible y la modifica. El error es difícil de detectar y el error causado puede ser completamente inesperado.

Lvalue y rvalue
Insertar descripción de la imagen aquí
El lado izquierdo del signo = es lvalue y el lado derecho del signo = es rvalue. El valor de la izquierda toma el espacio de memoria en cp+1 como se muestra arriba, y el valor de la derecha toma el valor del espacio de memoria;

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

Con respecto a ++++, ---- y otros operadores:
la forma en que el programa compilador se descompone en símbolos es: leer carácter por carácter.
Si el carácter puede formar un símbolo, luego lea el siguiente carácter hasta leer Los caracteres ingresados
​​no ya no forma un símbolo significativo. Este proceso se denomina "método codicioso".
Por ejemplo: int a=1,b=2;c;
c=a+++b;/∥ es equivalente a a+++b
d=a++++b;/∥ es equivalente a af+++ b, error

Insertar descripción de la imagen aquí
Almacenamiento de código y datos en programas C++;

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

RAlI (La adquisición de recursos es inicialización) :
un método de gestión de recursos exclusivo de C++. Algunos otros lenguajes, como Rust, también han adoptado RAII, pero entre los principales lenguajes de programación, C++ es el único que depende de RAII para la gestión de recursos. RAlI se basa en pilas y destructores para gestionar todos los recursos, incluida la memoria del montón.
El uso de RAll permite a C++ administrar la memoria de manera efectiva sin requerir un método de recolección de basura similar a Java. La existencia de RAll es también la razón principal por la que, aunque en teoría la recolección de basura se puede utilizar en C++, nunca se ha vuelto realmente popular.
RAll tiene algunos representantes de punteros inteligentes relativamente maduros: como std:auto_ptr y boost:shared_ptr

Insertar descripción de la imagen aquí

Problema de pérdida de memoria (pérdida de memoria) ¿
Qué es un problema de pérdida de memoria?
Se refiere a la memoria de montón asignada dinámicamente en el programa que no se libera o no se puede liberar por algún motivo, lo que
resulta en un desperdicio de memoria del sistema y hace que el programa se ralentice. caída o incluso caída del sistema como resultado de.
Causas y métodos de solución de problemas de pérdidas de memoria:
1. Las pérdidas de memoria ocurren principalmente en el método de asignación de memoria del montón, es decir, "una vez configurada la memoria,
se pierden todos los punteros que apuntan a la memoria". Sin un mecanismo de recolección de basura como el lenguaje, dichos
fragmentos de memoria no pueden devolverse al sistema.
2. Debido a que las pérdidas de memoria son problemas durante la ejecución del programa y no se pueden identificar mediante la compilación,
solo se pueden identificar y diagnosticar durante la ejecución del programa.

En C++ se introducen cuatro punteros inteligentes de uso común:
Unique_ptr, Shared_ptr, Weil_ptr;
Auto_ptr: obsoleto en C++ 11 y oficialmente eliminado en C++ 17;

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Problemas de uso
Insertar descripción de la imagen aquí
Problemas de propiedad
Insertar descripción de la imagen aquí
Referencias circulares: el recuento de referencias genera problemas de referencia circulares, lo que hace que la memoria del montón no se pueda reciclar normalmente, lo que provoca pérdidas de memoria.

Insertar descripción de la imagen aquí

referencia de C ++
Insertar descripción de la imagen aquí

Para tipos básicos en funciones, pasar por valor es más eficiente y para tipos personalizados, pasar por referencia a constante es más eficiente;

Elimine los indicadores "salvajes"
que apuntan a la memoria "basura". Los juicios If y otros no funcionan porque no se establece NULL,
generalmente hay tres situaciones:
1. Las variables de puntero no se inicializan,
2. Los punteros que se han liberado y no se han utilizado no se establecen en NULL, como los punteros después de eliminar y gratis
3. Las operaciones de puntero exceden el alcance de la variable;

Notas sobre el uso de punteros: establezca el valor en NULL para
punteros no inicializados, no utilizados o fuera de rango . (Es difícil, los punteros se utilizan en varios lugares y es difícil determinar cuándo ya no son necesarios. Solución: punteros inteligentes)

El puntero nulo es un puntero a nulo y se utiliza para las variables del puntero de inicialización de la memoria. El número de memoria 0 ~ 255 es la memoria ocupada por el sistema y es inaccesible; el puntero salvaje es un puntero que apunta
a un espacio de memoria ilegal. Ambos accesos deben informar un error, pero la ejecución bajo Dev es el siguiente Código: Se compila correctamente y aún puede ejecutarse, pero no hay resultados. La ventana se cierra automáticamente después de ejecutarse durante un período de tiempo. ¿Por qué sucede esto?

#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;
}

Aunque la sintaxis es correcta y puede pasar el compilador, debido a violaciones de acceso a la memoria causadas por la eliminación de referencias de punteros nulos y punteros salvajes, el sistema operativo finaliza la ejecución del programa para proteger el sistema.

Insertar descripción de la imagen aquí
El método de almacenamiento real de la máquina: los números positivos se almacenan directamente y los números negativos retienen el bit de signo e invierten el bit a bit +1;
big endian se usa comúnmente en Internet y se ajusta a los hábitos de lectura humanos, y la mayoría usa little endian PC personales y se ajusta a la máquina;

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
¡Esto es muy importante y debe tenerse en cuenta! ! !
Insertar descripción de la imagen aquí
La estructura sdshdr diseñada en Redis tiene una variable len para almacenar la longitud de la cadena, que no necesita ser recorrida para calcularla, existe una opción gratuita para administrar la capacidad restante, si la capacidad no es suficiente, automáticamente expandirá y modificará la tamaño de lente;

consejos y referencias

Insertar descripción de la imagen aquí

Matriz de punteros, cada uno de este conjunto es un puntero. T *t[ ]
puntero de matriz (un puntero a una matriz), este puntero apunta a una matriz. T (*t) [ ]

Insertar descripción de la imagen aquí
En el tercer ejemplo, primero observe el carácter izquierdo de la primera modificación constante, lo que significa que el valor del puntero no se puede cambiar, y luego observe la segunda modificación constante de *, lo que significa que la orientación del puntero no se puede cambiar;

Hay tres situaciones en las que los punteros se modifican constantemente.

  1. puntero modificado constante: puntero constante (el puntero al que apunta se puede cambiar, pero el valor al que se apunta no se puede cambiar)
  2. constante modificada constante - constante del puntero (el puntero no se puede cambiar, el valor del puntero se puede cambiar)
  3. const modifica punteros y constantes (ninguno de los dos se puede cambiar)

Mire si el lado derecho de const es un puntero o una constante. Si es un puntero, es un puntero constante. Si es una constante, es un puntero constante.

const se usa a menudo para evitar el mal uso

puntero inteligente

La memoria en el área del montón debe liberarse manualmente; de ​​lo contrario, se producirán pérdidas de memoria;

Solución: los punteros inteligentes son plantillas de clase. Cree un objeto de puntero inteligente en la pila, entregue el puntero ordinario al objeto de puntero inteligente y, cuando el objeto de puntero inteligente caduque, llame al destructor para liberar la memoria del puntero ordinario.

Unique_ptr: el objeto apuntado exclusivamente a
Shared_ptr:
wear_ptr:

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

3. Biblioteca C++STL

La relación entre los seis componentes principales de la biblioteca stl.
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

envase

Los contenedores se utilizan para almacenar datos;
los contenedores STL se dividen en dos categorías: Contenedores
de secuencia :
todos los elementos que contienen se pueden ordenar (ordenados). STL proporciona vectores, listas, deque y otros contenedores de secuencias, mientras que pila, cola, cola_prioridad es el contenedor. adaptador; Contenedores
asociativos :
Cada elemento de datos se compone de una clave (clave) y un valor (Valor). Cuando el elemento se inserta en el contenedor, presione su tecla de alguna manera. Las reglas específicas se colocan en la ubicación adecuada; STL común contenedores asociados tales como: conjunto, multiconjunto, mapa, multimapa;

#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;
}

**Muy importante tener en cuenta: **Tenga cuidado con los problemas de falla del iterador, como iter = Studentlevel.earse(''cc''); elimine el valor con la clave cc y devuelva el iterador en la siguiente posición; (*it)
. vacío(); simplificado->empty();

Para cualquier cuerpo de bucle que utilice un iterador, no agregue elementos al contenedor al que pertenece el iterador;
por ejemplo, push_back puede hacer que el iterador del objeto vectorial deje de ser válido;
por ejemplo, un bucle range for agrega elementos al vector .

funtor

  • Los functores generalmente no se usan solos, principalmente para usarse con algoritmos STL.
  • Los punteros de función no pueden cumplir con los requisitos de abstracción de STL, no pueden cumplir con los requisitos de los componentes básicos de software y no pueden combinarse con otros componentes de STL;
  • La esencia es que la clase sobrecarga un operador() y crea un objeto que se comporta como una función.

Desde puntero de función->genéricos->functor->plantilla de functor; perezoso

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);

}

Si el tipo de datos cambia, es necesario sobrecargar muchas funciones, lo cual es demasiado problemático, por lo que aparecieron los 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>);
}

Luego está el 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());
}

La siguiente es la plantilla de funtor: no es necesario agregar el tipo básico, pero se puede agregar si el consumo de objetos es 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

Los algoritmos en STL se dividen aproximadamente en cuatro categorías: incluidos en,,
1. Algoritmos de secuencia no variable: se refiere a algoritmos que no modifican directamente el contenido de los contenedores que operan;
2. Algoritmos de secuencia variable: se refiere a aquellos que pueden modificar el contenido de los contenedores que operan. Algoritmos;
3. Algoritmos de clasificación: incluyendo algoritmos para ordenar y fusionar secuencias, algoritmos de búsqueda y operaciones de conjunto en secuencias ordenadas;
4. Algoritmos numéricos: realizar cálculos numéricos sobre el contenido de los contenedores;
los algoritmos más comunes incluyen :
búsqueda, clasificación y algoritmos generales, algoritmos de permutación y combinación, algoritmos numéricos, algoritmos de conjuntos y otros algoritmos

transform(); función de cálculo de contenedor; función estadística de conteo; binario_search(); búsqueda binaria;

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;
}

Implementación de la disposición completa de la escritura a mano.

Ingrese una cadena completa sin caracteres repetidos e imprima la disposición completa de los caracteres en la cadena
. Por ejemplo, ingrese 123 = 3 2 1 = 3.
Salida de la situación 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;
}

Se debe garantizar el orden de la matriz. Por ejemplo, next es de pequeño a grande. Si lo implementa usted mismo, no perderá la disposición. Prev está en orden de grande a pequeño. La disposición completa funciona next_permutation() y
prev_permutation () en stl;

sort
El algoritmo de clasificación de STL
utiliza QuickSort (clasificación rápida) cuando la cantidad de datos es grande, y los fusiona y clasifica por segmentos.
Una vez que la cantidad de datos segmentados es inferior a un cierto umbral (16), para evitar una carga adicional excesiva causada por la llamada recursiva de QuickSort, se utiliza InsertSort (clasificación por inserción).
Si el nivel de recursividad es demasiado profundo, se utilizará HeapSort (clasificación de montón).

iterador

De manera similar a los punteros inteligentes, un pequeño caso de gc escrito a mano utiliza el método iterador;

Código fuente abierto MyGC
Insertar descripción de la imagen aquí

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++;

Insertar descripción de la imagen aquí
El puntero que apunta al objeto contiene un recuento de referencias de referencia, pero usa una lista para registrar el puntero y libera todos los punteros en la lista al final para resolver el problema de referencia circular.
Insertar descripción de la imagen aquí

adaptador de contenedor

pila pila:
un contenedor "primero en entrar, primero en salir", la estructura de datos subyacente es deque;
cola de cola:
un contenedor "primero en entrar, primero en salir", la estructura de datos subyacente es deque;
cola de prioridad prioridad_queue:
una cola especial, que se puede ordenar en la cola (clasificación de montón), la estructura de implementación subyacente es vectorial o deque;

cola de prioridad

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;//大顶堆
	}
}

asignador de espacio

  • "Análisis del código fuente STL" Hou Jie, la versión SGI STL es más legible;
  • Desde la perspectiva del uso, el asignador funciona silenciosamente oculto en otros componentes y no necesita atención, pero desde la perspectiva de comprender la implementación de STL, es el componente que debe analizarse primero;
  • El análisis del asignador puede reflejar las ideas de optimización de C++ en la gestión del rendimiento y los recursos;

Resumen de STL
Los seis componentes principales de STL aportan nuevo polimorfismo y reutilización a la programación de software, y son la esencia de la eficiencia del lenguaje C++ moderno; el
camino de aprendizaje de los genéricos y STL es muy empinado, y se recomienda que los principiantes aprendan primero el uso básico y simple. extensiones;
Después de dominar una determinada base, puede mejorar sus capacidades estudiando y analizando más a fondo el código fuente y escribiendo sus propios componentes;

Otras bibliotecas

biblioteca boost La
biblioteca Boost es el nombre general de algunas bibliotecas C++ que proporcionan extensiones a la biblioteca estándar del lenguaje C++. Es desarrollada y mantenida por la organización comunitaria Boost. La biblioteca Boost puede funcionar perfectamente con la biblioteca estándar C++ y proporcionarle funciones extendidas. ; la biblioteca estándar de C ++ también está absorbiendo gradualmente algunas de sus funciones;
Boost se puede dividir aproximadamente en más de 20 categorías: bibliotecas de procesamiento de texto y cadenas, bibliotecas de contenedores, bibliotecas de algoritmos, objetos de función y bibliotecas de programación de alto orden, bibliotecas de clases integrales, etc. .;
sitio web oficial: https://www.boost.org/
Espejo: https://dl.bintray.com/boostorg/release/

Marco de aplicación HTTP Drogon basado en C++ 14/17 (el nombre de un dragón (Drogon) en "Juego de Tronos"): https://github.com/drogonframework/drogon/blob/master/README.zh- CN .Maryland

Documento chino traducido por grpc: https://doc.oschina.net/grpc?t=58008 (marco RPC multiplataforma), explicación: https://juejin.cn/post/7047885453336248327

Marco rpc de código abierto de 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. Patrones de diseño de C++

Hay 23 patrones de diseño reutilizables y orientados a objetos comunes en software que brindan soluciones generales a algunos problemas comunes basados ​​en experiencias previas.
Los patrones de diseño también tienen costos y escenarios aplicables, pero no son omnipotentes. Estos 23 tipos son en realidad adecuados para escenarios que tienen una gran escalabilidad y se usarán repetidamente en una gran cantidad de escenarios con algunos cambios en el futuro;

Patrón singleton

Insertar descripción de la imagen aquí

Patrón de observador

Insertar descripción de la imagen aquí
Ideas de implementación:
desacoplar las responsabilidades del problema, abstracto Observable y observador, y distinguir abstracción y entidad;

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;
}

¿Qué son void, NULL y nullptr?
void* es un tipo de puntero general que puede apuntar a cualquier tipo de datos. No está directamente relacionado con un tipo de datos específico, por lo que no se puede desreferenciar y requiere una conversión de tipo explícita para su uso. Por ejemplo:

void* ptr = nullptr; // ptr es un puntero nulo
int* intPtr = static_cast<int*>(ptr); // Convertir puntero void en puntero int
En versiones anteriores de C++, NULL se definía como el entero 0. Esto significa que se puede utilizar como puntero al valor nulo. Sin embargo, el uso del número entero 0 puede generar cierta ambigüedad, ya que 0 también puede ser un valor de otros tipos de números enteros. En C++ moderno, se recomienda utilizar nullptr en lugar de NULL. Por ejemplo:

int* ptr = nullptr; // ptr es un puntero nulo
nullptr es una palabra clave introducida en C++11 para representar un puntero nulo. nullptr tiene mejor seguridad de tipos en comparación con NULL. Es implícitamente convertible a cualquier tipo de puntero y no se puede confundir con otros tipos de números enteros. Por ejemplo:

int* ptr = nullptr; // ptr es un puntero nulo

Un puntero es una variable que se utiliza para almacenar una dirección de memoria y se puede acceder a los datos apuntados a través del operador de desreferencia *. Un puntero nulo significa que el puntero no apunta a ninguna dirección de memoria válida. En C++, estos conceptos se pueden utilizar para manejar cómodamente la situación en la que el puntero es nulo y evitar errores o comportamientos indefinidos.

Insertar descripción de la imagen aquí
Los 23 patrones de diseño orientado a objetos se clasifican aproximadamente en patrones creativos, estructurales y de comportamiento; los
patrones de diseño no son omnipotentes, se basan en puntos de cambio del sistema y pueden usarse dondequiera que haya cambios; los
patrones de diseño se están desacoplando y, para expandirse, generalmente evoluciona y necesita evolución para
posicionarse con precisión;
el patrón de diseño es un método de diseño de software, no un estándar. En la actualidad, la mayoría de los marcos actuales ya contienen
una gran cantidad de ideas de patrones de diseño;

Programación genérica

Insertar descripción de la imagen aquí

Si la orientación a objetos es un método para llamar funciones a través de una capa indirecta a cambio de una abstracción, entonces la programación genérica es una abstracción más directa, que no pierde eficiencia debido a la capa indirecta; a diferencia del polimorfismo dinámico orientado a objetos, la programación genérica
es una especie de polimorfismo estático, que genera el código más directo a través del compilador en el momento de la compilación;
la programación genérica puede separar algoritmos de tipos y estructuras específicos y reutilizar el código tanto como sea posible;

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;
}

El compilador creará una instancia de función de plantilla correspondiente en función de los tipos de parámetros reales pasados ​​a la función.

La relación entre genéricos, polimorfismo y sobrecarga: Los genéricos pueden mejorar la reutilización del código, pero no involucran directamente los conceptos de polimorfismo o sobrecarga. El polimorfismo se refiere a la característica que permite que objetos de diferentes clases respondan al mismo mensaje, mientras que la sobrecarga se refiere a permitir múltiples funciones con el mismo nombre pero diferentes listas de parámetros en el mismo alcance. Aunque los genéricos pueden mejorar la reutilización del código, no afectan directamente estos conceptos.

Este ejemplo demuestra los genéricos. La función max no necesita cambiar de tipo repetidamente. En su lugar, el compilador genera llamadas a funciones basadas en los parámetros y plantillas pasados. Sin embargo, si la función genérica no satisface nuestras necesidades, debe especializarse. . Puede interrumpir la depuración para ver qué función se está ejecutando.

Una vez que se comete un error en la programación genérica, ¡es difícil para los principiantes corregirlo! Porque el compilador hace muchas cosas automáticamente;

programación funcional;

transmisión_estática

Insertar descripción de la imagen aquí

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

Insertar descripción de la imagen aquí

patrón adaptador

Reutilizar las funciones del código original, no cambiar y luego crear nuevas funciones.
La herencia múltiple es muy mala. Tiene algo que ver con C ++,
problemas de herencia de diamantes y herencia virtual.

El primero: usar herencia múltiple.
El segundo: usar combinación para crear instancias de objetos de la clase original como variables miembro de la nueva clase.

Supongo que te gusta

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