当前位置:网站首页>The underlying principles and templates of new and delete

The underlying principles and templates of new and delete

2022-07-08 00:09:00 __ cplusplus

Main contents of this paper :

  • new and delete The underlying principle of
  • What is a template
  • How to use templates
  • Can a template be declared and defined in two files ?

new and delete The underlying principle of
We talked about new and delete Use , And the C In language malloc and free The difference between . however ,new and delete The processing of built-in types is different from malloc and free Very similar . Then it inevitably causes us to think : This new and delete How is the underlying layer of the ? The underlying implementation and malloc also free What is the relationship between ?
So let's start with that new The underlying principle of :

int main()
{
    
   int* pa=new int;
  return 0;
}

Go to disassembly in debug mode , Observe the corresponding assembly language :
 Insert picture description here
Here we see , We call new Operator . The compiler calls a function when converting :opreator new A function of , And this function is exactly new The underlying implementation of !
Let's take a look operator new Function source code implementation :

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
        {
           // try to allocate size bytes
        void *p;
        while ((p = malloc(size)) == 0)
                if (_callnewh(size) == 0)
                {
           // report no memory
                static const std::bad_alloc nomem;
                _RAISE(nomem);
                }
 
        return (p);
        }

From this source code, we can see ,operator new The essence of function is also encapsulated malloc Function of , And when the application for memory space fails, it no longer returns NULL, Instead, throw an exception ! It can be so simple to think ,operator new Functions fail and throw exceptions malloc!
therefore new It works like this :

Bottom call operator new Function to apply for space , After applying for space , Call the constructor of the corresponding class to initialize

Allied ,delete The underlying implementation principle of calls operator delete function , The corresponding is encapsulation free Function of .

Be careful : there operator new Not right new overloaded ! This is often misleading ! This operator new Is a separate function , If you need to call, write it out explicitly opreator new!

// Display call operator new
#include<iostream>
using namespace std;
int main()
{
    
	int* pa = new int;
	// Explicit calls must be like this !
	void* pa = operator new(sizeof(int));
	return 0;
}

operator delete Source code :

void operator delete(void* pUserData)
{
    
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); /* block other threads */
	__TRY
		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
		return;
}

C++ The official database corresponds to operator new[] function , Those who are interested can learn by themselves , No more mention here .


What is a template
We know C++ Have the idea of object-oriented programming , One of the most classic is C++ Of Generic Programming , The template is the prerequisite for generic programming . Then let's think about what a template is ?
First , We make experimental reports everyday . The corresponding teachers will ask us to write in a certain format . Usually the teacher will send a sample to us for reference , This example is Templates


Use of templates
In contact, we are learning C When it comes to language ,C Some deficiencies of language .
First C The first deficiency of the language is that it does not support overloading , Let's write a swap function , We need to give different names to different types
and C++ Language provides the mechanism of function overloading , It solves the problem that we don't have to name functions anymore .. But it still needs to write a lot of redundant and repetitive code . To solve such problems .C++ The mechanism of template is introduced , The work of generating corresponding functions is entrusted to the compiler rather than the programmer .

// Syntax of template ---->template keyword 
// Use a template to write swap function 
template<typename T>
void swap(T& a,T& b)
{
    
   T tmp=a;
   a=b;
   b=tmp;
}
int main()
{
      int a=2,b=1;
  swap(a,b);
  double c=1.0,d=2.0;
  swap(c,d);
  return 0;
}

 Insert picture description here
It is not difficult to see , The compiler automatically deduces the corresponding Swap Version of function ! The template used here is function template , The function to be generated can be automatically deduced according to the parameter type
So let's look at such a code

int Add(const int x, const int y)
{
    
	return x + y;
}
template<typename T>
T Add(const T& x, const T& y)
{
    
	return x + y;
}
int main()
{
       
	Add(3, 2);
	Add(3.0, 2.0);
	return 0;
}

 Insert picture description here
You can see that the first call here calls the existing function Add, Instead of extrapolating .
in other words , If the existing function already has a function that can meet the call requirements , The compiler preferentially calls the matching ! If you can't find it, you will consider the deduction code .
If you want the compiler to deduce , The transformation can be called in this way .

int Add(const int x, const int y)
{
    
	return x + y;
}
template<typename T>
T Add(const T& x, const T& y)
{
    
	return x + y;
}
int main()
{
       
	Add<int>(3, 2);// The compiler will deduce the version 
	Add(3.0, 2.0);
	return 0;
}

This template is called a function template , There is also a template called class template . Class template in our study STL Will be exposed to more ! Let's first look at the syntax definition of the class template

// Use of class templates 
#include<iostream>
using std::cout;
using std::endl;
// Angle brackets can also be used class, But never use struct
template<typename T>
class vector
{
    
public:
	vector(size_t capacity=10)
		: _a(new T[capacity])
		,_size(0)
		,_capacity(capacity)
	{
    }
private:
	T* _a;
	size_t _size;
	size_t _capacity;
};
int main()
{
       // The class template must show the type that provides the derivation !
	vector<int>v;
	return 0;
}

Sometimes you can also separate declarations from definitions , However, the separation of declaration and definition here is limited to declaration and definition in the same file , At this time, let's see how to deal with

// Declaration and definition are separated in the same file 
#include<iostream>
using std::cout;
using std::endl;
template<typename T>
class vector
{
    
public:
	vector(size_t capacity=10)
		: _a(new T[capacity])
		,_size(0)
		,_capacity(capacity)
	{
    }
	void push_back(const T& e);
private:
	T* _a;
	size_t _size;
	size_t _capacity;
};
// The separation definition also requires a template declaration ,
// And the class domain to which it belongs becomes vector<T>
template<typename T>
void vector<T>::push_back(const T& e)
{
    
	_a[_size++] = e;
}
int main()
{
       
	vector<int>v;
	return 0;
}

Can a template be declared and defined in two files ?
First , Give a clear answer first : Don't put the declaration and definition of the template class in two files !
To verify this practice , We write two documents vector.h ,vector.cpp To verify whether it can be separated :

//vector.h  Release statement 
#pragma once
#include<iostream>
using std::cout;
using std::endl;
template<typename T>
class vector
{
    
public:
	vector(size_t capacity = 10)
		: _a(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{
    }
	void push_back(const T& e);
private:
	T* _a;
	size_t _size;
	size_t _capacity;
};
//vector.cpp
#include "vector.h"
template<typename T>
void vector<T>::push_back(const T& e)
{
    
	_a[_size++] = e;
}
template<typename T>
vector<T>::~vector()
{
    
	delete[] _a;
	_size = 0;
	_capacity = 0;
}
//main.cpp
#include "vector.h"
int main()
{
       
	vector<int>v1;
	vector<double>v2;
	v1.push_back(1);
	v2.push_back(2.0);
	return 0;
}

 Insert picture description here
We found that , It happened. link error , Let's see why there are link errors
Let's look at it from the place of invocation , Function calls eventually become call An address , This address is the function address in the symbol table generated by the previous compilation . However , The template is just an empty shell ,** After compiling ,vector.h and vector.cpp The symbol table of is empty !** therefore , Unable to find the address of the function in the corresponding symbol table , So there is a link error !
Solution : stay vector.cpp The file shows instantiation !

// Explicitly instantiate ---> Tell the compiler to deduce like this 
template void vector<int>::push_back(const int& e);
// Explicitly instantiate 
template void vector<double>::push_back(const double& e);
// Show instantiated classes 
template class vector<int>;
template class vector<double>;

Because the cost of separating declaration and definition in two files is very high , So our recommendation is not to separate the declaration and definition of template classes in two files , And used to .h Change to .hpp


summary :

  • new and delete The underlying principle is operator new/delete, This is a library function, not right new/delete overloaded , It can be understood as failure throwing exception malloc/free.
  • Templates are the foundation of generic programming
  • Syntax of template
  • Templates do not support the separation of declarations and definitions in two files , The cost is very high !

I hope you can make progress together , If there is any deficiency, please point out .

原网站

版权声明
本文为[__ cplusplus]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/189/202207072159361984.html