C++ Primer (5.ª edición) Notas de estudio clave para todo el libro

Tabla de contenido

Capítulo 12 Memoria dinámica

12.1 Memoria dinámica y punteros inteligentes

12.1.6 débil_ptr

12.2 Matrices dinámicas

12.2.1 nuevos y arreglos

12.2.2 clase de asignador


 

Capítulo 12 Memoria dinámica

12.1 Memoria dinámica y punteros inteligentes

12.1.6 débil_ptr

débil_ptr es un puntero inteligente que no controla la vida útil del objeto al que apunta, apunta a un objeto administrado por un shared_ptr. Vincular un ptr débil a shared_ptr no cambia el recuento de referencias de shared_ptr. Una vez que se destruye el último shared_ptr que apunta al objeto, el objeto se libera.

Cuando creamos un ptr débil, lo inicializamos con un ptr compartido:

auto p = make_shared<int>(42);
weak_ptr<int> wp(p);

Dado que es posible que el objeto no exista, no podemos usar débil_ptr para acceder directamente al objeto, pero debemos llamar a lock para verificar si el objeto señalado por débil_ptr todavía existe. Si está presente, lock devuelve un ptr compartido que apunta al objeto compartido.

if (shared_ptr<int> np = wp.lock()) { 
    // 只有当1ock调用返回true时我们才会进入if语句体
}

12.2 Matrices dinámicas

12.2.1 nuevos y arreglos

Para que new pueda asignar una matriz de objetos, seguimos el nombre del tipo con un par de corchetes, en los que especificamos la cantidad de objetos que se asignarán. Los tamaños entre corchetes deben ser números enteros, pero no es necesario que sean constantes.

//调用get size确定分配多少个int
int *pia = new int[get size()]; //pia指向第一个int

También es posible asignar una matriz con un alias de tipo que indique el tipo de la matriz, de modo que los corchetes no sean necesarios en la nueva expresión:

typedef int arrT[42];    //arrT表示42个int的数组类型
int *p = new arrT;    //分配一个42个int的数组;p指向第一个int
int *p = new int[42];   //编译器执行这个表达式时还是会用new[]

 Uso de typedef: 【C/C++】【typedef】Enciclopedia de uso_Uso de typedef en C++

Al asignar una matriz con new, no obtenemos un objeto del tipo de matriz, sino un puntero del tipo de elemento de matriz. Incluso si definimos un tipo de matriz utilizando un alias de tipo, new no asignará un objeto de tipo de matriz. En el ejemplo anterior, new devuelve un puntero a un tipo de elemento.
Dado que la memoria asignada no es un tipo de matriz, no puede llamar a begin o end en una matriz dinámica. Estas funciones usan las dimensiones de la matriz para devolver punteros al primer y último elemento. Por la misma razón, la instrucción range for no se puede utilizar para procesar elementos en matrices dinámicas.

Inicializar matrices de objetos asignados dinámicamente: de forma predeterminada, los objetos asignados por new, ya sea individualmente o en una matriz, se inicializan de forma predeterminada. Los elementos de una matriz se pueden inicializar con valor siguiendo el tamaño con un par de paréntesis vacíos. En el nuevo estándar, también podemos proporcionar una lista entre llaves de inicializadores de elementos.

int* pia = new int[10];    //10个未初始化的int
int* pia2 = new int[10]();   //10个值初始化为0的int       
    
int* pia3 = new int[10]{ 0,1,2,3,4,5,6,7,8,9 };   //10个1nt分别用列表中对应的初始化器初始化
string* pia4 = new string[10]{ "a","an","the",string(3,'x') };   //10个string,前4个用给定的初始化器初始化,剩余的进行值初始化

Es legal asignar dinámicamente una matriz vacía: cuando usamos new para asignar una matriz de tamaño 0, new devuelve un puntero legal no nulo, pero este puntero no se puede desreferenciar; después de todo, no apunta a ningún elemento.

char arr[0];     // 错误:不能定义长度为0的数组
char* cp = new char[0];      //正确:但cp不能解引用

Liberar una matriz dinámica: para liberar una matriz dinámica, usamos una forma especial de eliminar que precede al puntero con un par de corchetes vacíos. Se requiere el par de corchetes vacíos cuando liberamos un puntero a una matriz: le indica al compilador que este puntero apunta al primer elemento de una matriz de objetos. Si omitimos los corchetes al eliminar un puntero a una matriz, el comportamiento no está definido.

delete cp;    // p必须指向一个动态分配的对象或为空
delete [] cp;    //pa必须指向一个动态分配的数组或为空

Punteros inteligentes y matrices dinámicas: la biblioteca estándar proporciona una versión de unique_ptr que puede administrar matrices recién asignadas. Para
administrar una matriz dinámica con un único_ptr, debemos seguir el tipo de objeto con un par de corchetes vacíos.

No podemos usar operadores de membresía de punto y flecha cuando un ptr único apunta a una matriz. Después de todo, el ptr único apunta a una matriz y no a un solo objeto, por lo que estos operadores no tienen sentido. Cuando un ptr único apunta a una matriz, podemos usar el operador de subíndice para acceder a los elementos de la matriz.

// up指向一个包含10个未初始化int的数组	
unique_ptr<int[]> up(new int[10]);
for (size_t i = 0; i != 10; ++i) {
	up[i] = i;
	cout << "up" << "[" << i << "]:" << up[i] << endl;
}
//自动用delete[]销毁其指针
up.release();

A diferencia de unique_ptr, shared_ptr no admite directamente la gestión de matrices dinámicas. Si desea utilizar shared_ptr para administrar una matriz dinámica, debe proporcionar su propio eliminador definido.

shared_ptr no define un operador de subíndice y el tipo de puntero inteligente no admite la aritmética de punteros. Por lo tanto, para acceder a los elementos de la matriz, debe usar get para obtener un puntero incorporado y luego usarlo para acceder a los elementos de la matriz.

 

12.2.2 clase de asignador

Clase de asignador: la clase de asignador de biblioteca estándar se define en la memoria del archivo de encabezado, lo que nos ayuda a separar la asignación de memoria de la construcción de objetos. Proporciona un método con reconocimiento de tipos para asignar memoria sin procesar y sin construir.

Para definir un objeto asignador, debemos especificar los tipos de objetos que el asignador puede asignar. Cuando un objeto asignador asigna memoria, determina el tamaño de memoria y la alineación adecuados para el tipo de objeto dado.

allocator<string> alloc;    //可以分配string的allocator对象
auto const p = alloc.allocate(8);    //分配n个未初始化的string

El asignador asigna memoria no construida: la memoria asignada por el asignador no está construida. Construimos objetos en esta memoria según sea necesario. En la nueva biblioteca estándar, la función miembro de construcción toma un puntero y cero o más argumentos adicionales y
construye un elemento en la posición dada.

auto q = p;    // q指向最后构造的元素之后的位置
alloc.construct(q++);    //*q为空字符串
alloc.construct(q++, 10, 'c');    //*q为cccccccccc
alloc.construct(q++, "hi");    //*g为hi!

Para usar la memoria devuelta por allocate, debemos construir el objeto con construct. Con la memoria no construida, el comportamiento no está definido.

Cuando hayamos terminado con el objeto, debemos llamar a destroy en cada elemento construido para destruirlos. La función destroy acepta un puntero y ejecuta el destructor en el objeto apuntado:

while(q!=p)
    alloc.destroy(--q);  //释放我们真正构造的string

Al comienzo del ciclo, q apunta a la posición posterior al último elemento construido. Decrementamos q antes de llamar a destroy. Por tanto, la primera vez que se llama destruir, q apunta al último elemento construido. En el último paso del ciclo, destruimos el primer elemento construido, luego g será igual a p, y el ciclo termina. 

La liberación de memoria se realiza llamando a desalocate

alloc.deallocate(p, n);

Algoritmos para copiar y llenar la memoria no inicializada  : la biblioteca estándar también define dos algoritmos complementarios para la clase de asignador, que pueden crear objetos en la memoria no inicializada, ambos definidos en la memoria del archivo de encabezado.

copia_no inicializada(b,e,b2) Copia elementos del rango de entrada señalado por los iteradores b y e a la memoria sin procesar especificada por el iterador b2. La memoria a la que apunta b2 debe ser lo suficientemente grande como para contener una copia de los elementos en la secuencia de entrada
copia_no_inicializada_n(b,n,b2) A partir del elemento al que apunta el iterador b, copie n elementos en la memoria a partir de b2
relleno_no inicializado(b,e,t) Cree un objeto en el rango de memoria original especificado por los iteradores b y e, y el valor del objeto es una copia de t
uninitialized_fill_n(b,n,t) Cree n objetos a partir de la dirección de memoria a la que apunta el iterador b. b debe apuntar a una memoria sin procesar lo suficientemente grande como para contener el número dado de objetos

Supongo que te gusta

Origin blog.csdn.net/qq_41921826/article/details/132004307
Recomendado
Clasificación