Gestión de memoria C/C++ (explicación detallada nueva y eliminada)

introducción

En la parte anterior del lenguaje C, hemos introducido la división de las áreas de almacenamiento en la memoria: incluido el espacio del kernel (el código de usuario no puede acceder), la pila, el segmento de asignación de memoria (asignación de archivos, biblioteca dinámica, asignación anónima), montón, segmento de datos ( área estática), segmento de código (área constante) .
Y puede usar hábilmente malloc, calloc, realloc y free para la gestión dinámica de la memoria:
Detalles de la gestión dinámica de la memoria en lenguaje C

Pero en C++, al usar estas funciones para la gestión dinámica de la memoria, no se pueden cumplir algunos requisitos (como inicializar objetos al solicitar espacio) y es más problemático de usar. Entonces C ++ propone una forma de solicitar newespacio dinámicamente delete:

El uso de nuevo y eliminar

A diferencia de malloc y free, new y delete son operadores en lugar de funciones .

Al usar new y delete para solicitar espacio:
para un solo elemento, use new 类型;para solicitar un espacio de un tipo específico, y el valor de la expresión es un puntero a este espacio. Puede usar paréntesis después del tipo para inicializar el valor de este tipo new 类型(初始值);;
correspondientemente, necesita usar delete 指针;el formulario para liberar el espacio de este único elemento.

Para elementos continuos, use new 类型[num];para solicitar un espacio continuo de num tipos, y el valor de la expresión es la dirección de este espacio. Puede usar {} después de [num] para inicializar este espacio: new 类型[num]{};;
En consecuencia, debe usar delete[] 指针;el formulario para liberar el espacio de este elemento continuo.

tipo incorporado

De acuerdo con las reglas presentadas anteriormente, los siguientes códigos están disponibles para el espacio de aplicación dinámico del tipo incorporado:

int main()
{
    
    

	int* p1 = new int;  
	//动态开辟一块int的空间,不初始化
	int* p2 = new int(10);  
	//动态开辟一块int的空间,初始化为10
	int* p3 = new int[10];  
	//动态开辟一块10个int的空间,不初始化
	int* p4 = new int[10]{
    
     1,2,3,4,5,6,7,8,9,0 }; 
	//动态开辟一块i10个int的空间,初始化为1,2,3,4,5,6,7,8,9,0

	delete p1;
	delete p2;
	//释放单个元素空间用delete
	delete[] p3;
	delete[] p4;
	//释放连续空间需使用delete[]

	return 0;
}

Podemos ver los valores en el espacio solicitado por cada parte mediante la depuración:

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Cabe señalar que newy delete, new []y delete[]no se pueden mezclar Aunque no habrá problemas al aplicar dinámicamente tipos integrados, el programa se bloqueará para tipos personalizados.

tipo personalizado

Para los tipos incorporados, el uso de malloc y free apenas puede satisfacer nuestras necesidades, pero para los tipos personalizados, como los tipos de clase, necesitamos inicializar los objetos de clase cuando solicitamos espacio y, obviamente, malloc no puede satisfacer nuestras necesidades.

Después de que new aplique dinámicamente el espacio, también llamará al constructor predeterminado; delete liberará el espacio aplicado dinámicamente después de llamar al destructor.
Aquí debe prestar especial atención a la diferencia entre el espacio de los objetos de clase y el espacio de recursos en los objetos de clase :

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

Por ejemplo, esta clase A tiene dos variables miembro inty char*ocupa 8 bytes, estos 8 bytes son el espacio del objeto de la clase, este espacio puede estar en el área de la pila o aplicarse dinámicamente en el área del montón, según el usuario,
pero char*apunta a un espacio continuo. El tamaño de este espacio es incierto. Se aplica dinámicamente en el constructor cuando se instancia el objeto de la clase, que no puede ser cambiado por el usuario de la clase. Este espacio abierto dinámicamente es el recurso de la clase, que solo se puede aplicar en el constructor y liberar en el destructor. Esta es la razón por la cual malloc no puede satisfacer nuestro espacio de aplicaciones dinámicas para tipos personalizados.

inserte la descripción de la imagen aquí

Para el nuevo tipo personalizado, el uso es consistente con el tipo incorporado:
cuando se usa new para solicitar un solo objeto, el constructor se llama una vez, cuando se aplica para num objetos consecutivos, el constructor se llama num veces; delete es el mismo:

int main()
{
    
    
	A* pa1 = new A;
	//动态开辟一个对象,调用默认构造初始化
	A* pa2 = new A(5);
	//动态开辟一个对象,传参给构造函数初始化
	A* pa3 = new A[5];
	//动态开辟一块连续的类对象空间,全部调用默认构造初始化
	A* pa4 = new A[5]{
    
     1,2,3,4,5 };
	//动态开辟一块连续的类对象空间,分别传参初始化

	delete pa1;
	delete pa2;
	//释放单个元素空间用delete
	delete[] pa3;
	delete[] pa4;
	//释放连续空间需使用delete[] !!!

	return 0;
}

Podemos comprobar el estado de la aplicación dinámica mediante depuración:
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
se llama un total de 1+1+5+5=12 constructores y 12 destructores:
inserte la descripción de la imagen aquí

El principio de realización de new y delete

tipo incorporado

Si está solicitando un tipo de espacio incorporado, new y malloc, delete y free son básicamente similares. Sin embargo new, deletela aplicación y la liberación son para el espacio de un solo elemento, new []y delete[]la aplicación es para el espacio continuo, y newcuando el espacio de la aplicación falla, se lanzará una excepción y mallocse devolverá NULL.

Debe tenerse en cuenta que cuando se aplica o libera espacio de forma dinámica, C++ se inclina más a generar una excepción para reflejar la causa del error cuando falla la aplicación o la versión. Este comportamiento de lanzar una excepción se implementa en dos funciones operator new. También podemos verificar a través del desensamblado que cuando se crea un nuevo espacio, se llama a la nueva función del operador, y cuando se realiza la eliminación, se llama a la función de eliminación del operador: Por supuesto, al aplicar y liberar espacio continuo, la función y se llama. Sin embargo, estas dos funciones se implementan llamando a múltiples y .operator delete

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
operator new[]operator delete[]operator newoperator delete

Comprensión de las funciones de operador nuevo y de eliminación de operador

Podemos echar un breve vistazo a la función operator newAND operator delete:

new y delete son operadores para que los usuarios apliquen y liberen memoria dinámica. operator new y operator delete son funciones globales proporcionadas por el sistema. new llama a la nueva función global del operador en la capa inferior para solicitar espacio, y delete usa el operador delete global Función en la capa inferior para liberar espacio .

De hecho, el espacio de la aplicación operator newtambién se pasamalloc . Si el espacio de la aplicación malloc tiene éxito, regresará directamente. De lo contrario, se implementarán las contramedidas proporcionadas por el usuario por espacio insuficiente. Si el usuario proporciona esta medida, la aplicación continuará, de lo contrario, se lanzará una excepción. operator deleteEn última instancia, se trata freede liberar espacio .

tipo personalizado

  1. El principio de new
    Llame operator newa la función para solicitar el espacio y luego ejecute el constructor en el espacio aplicado para completar la construcción del objeto.

  2. El principio de eliminación
    Ejecuta el destructor en el espacio, completa la limpieza de recursos en el objeto y luego llama operator deletea la función para liberar el espacio del objeto.

  3. El principio de new T[num]
    llama operator new[]a la función, en realidad llama a la función en el operador new[] operator newpara completar la aplicación de num objetos espacios, y ejecuta el constructor num veces en el espacio aplicado

  4. El principio de delete[]
    Ejecute num destructores en el espacio de objetos liberados, complete la limpieza de recursos en num objetos y luego llame al operator delete[]espacio de liberación, que en realidad se llama en el operador delete[] operator deletepara liberar el espacio

posicionamiento nuevo

Localizar nuevo puede usar una pieza de espacio dinámico que se ha aplicado para llamar al constructor para inicializar el objeto de clase

La ubicación de nuevos se usa generalmente junto con el grupo de memoria (el grupo de memoria es un espacio que se ha solicitado con anticipación. Solicitar una parte del espacio con anticipación puede evitar la reducción en la eficiencia causada por el espacio de aplicación frecuente debido a la expansión frecuente ).El espacio en el grupo de memoria es solo para la aplicación, no para la inicialización, podemos lograr la inicialización ubicando nuevo:

El formato de uso del posicionamiento nuevo es: new (要初始化的空间的指针) 类型;, cabe señalar que si el tipo de clase a inicializar no tiene un constructor por defecto, se deben pasar parámetros; new (要初始化的空间的指针) 类型(构造函数参数列表);al
liberar los recursos del objeto de clase inicializado por posicionamiento nuevo, es necesario llame explícitamente al objeto de clase El destructor para desasignar:

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

int main()
{
    
    
	A* ptr = (A*)malloc(1000);
	//创建1000个字节的空间
	new(ptr)A(5);
	//用上面申请的空间初始化一个A对象
	ptr->~A();
	//释放上面定位new初始化的对象的资源
	free(ptr);
	//释放malloc出的空间
	return 0;
}

El punto a tener en cuenta es la diferencia entre el espacio de clase y el espacio de recursos de clase : aquí malloc solo se aplica a una parte del espacio, y la siguiente novedad es inicializar el espacio en malloc. Este comportamiento de inicialización incluye la solicitud de recursos de clase, que no pertenecen a malloc fuera del espacio;
delete libera los recursos de la clase, y free pierde el espacio fuera de malloc.

La diferencia entre new&delete y malloc&free

  1. malloc y free son funciones; new y delete son operadores

  2. El espacio solicitado por malloc no se inicializará; se puede inicializar nuevo

  3. Cuando malloc solicita espacio, debe calcular manualmente el tamaño del espacio y transferirlo; new solo debe ir seguido del tipo de espacio. Si hay varios objetos, especifique el número de objetos en [num]

  4. El valor de retorno de malloc void*debe ser forzado cuando se usa; new no lo necesita, porque el tipo de espacio se especificará después de new

  5. Cuando malloc no puede solicitar espacio, devuelve NULL, por lo que debe considerarse vacío al usarlo; new no lo necesita, pero new necesita detectar excepciones

  6. Al solicitar un tipo de objeto personalizado, malloc/free solo abrirá espacio y no llamará al constructor ni al destructor; mientras que new llamará al constructor para completar la inicialización del objeto después de solicitar espacio, y delete llamará al destructor antes de liberar el espacio Complete la limpieza de recursos en el espacio

Resumir

En este punto, la introducción de la administración de memoria C/C++ ha terminado.
Creo que no solo ha aprendido el uso de new y delete en C++, sino que también ha profundizado su comprensión de la administración de memoria.

Si cree que no presenté una parte determinada claramente o que hay un problema con una parte determinada, puede plantearlo en el área de comentarios.

Si este artículo es útil para usted, espero que se conecte con un solo clic.

Espero progresar junto con usted.

Supongo que te gusta

Origin blog.csdn.net/weixin_73450183/article/details/131139176
Recomendado
Clasificación