Memory management + function template and class template

Posted by brash on Sun, 26 Sep 2021 21:33:51 +0200

The difference between global variables and global static variables: link attributes are different. globavar is visible in all files, while global static is only visible in this file.
Relationship between malloc - > operator new - > New
malloc new = malloc + failure throw exception; Throw exception (object-oriented way to handle errors)
new = operator new + constructor.
Date *p=operator new (sizeof(A)) plus new (P) date is equivalent to
Date *p = new Date;
new is different from malloc:
1.new will call the function to construct initialization. 2. Exceptions will be thrown when new fails. 0 will be returned if malloc fails;
Where delete is different from free:
1. Call the destructor (clean up resources) for processing.
2. When delete fails, the process will automatically terminate.
operator delete is no different from free: failure to free space will directly terminate the process.
The difference between malloc/free and new/delete
1. Conceptual properties: malloc and free are functions, and new and delete are operators
2. Usage: malloc needs to calculate the space size and pass parameters when applying for space. new only needs to follow the space type.
3. Usage effect: when malloc fails to apply for space, it returns NULL, so it must be NULL when using. New does not need it, but new needs to catch exceptions.
When applying for and releasing custom type objects, malloc/free will only open up space and will not call constructors and destructors, while new and delete will.

Template

1. Generic template: use the template to write type independent code.
Template principle: we write a template ourselves, and the compiler generates relative functions through the template.

2. Instantiation of function template
The instantiation of function templates can be divided into implicit instantiation and display instantiation.
Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters.
For example: Add (a1, a2)
If the function template is

Add(const T& left,const T& right)

At this time, if the types of a1 and a2 are different, a compilation error will occur.
At this time, there are two methods
1. The user can forcibly convert Add (a, (int) d)
2. Explicitly instantiate Add(a1,a2)

Matching principle of template parameters

1. A non template function can exist simultaneously with a function template with the same name, and the function template can also be instantiated as this non template function.
2. For non template functions and function templates with the same name, if other conditions are the same, the non template function will be called first during transfer, and an instance will not be generated from the template. If the template can produce a function with a better match, the template will be selected.
3. Template functions do not allow automatic type conversion, but ordinary functions can perform automatic type conversion.
Implementation of dynamic sequence table:

#include<iostream>
#include<assert.h>
using namespace std;
#define N 5
template<class T>
class vector//Dynamic sequence table
{
public:
	vector(int size = 0, int capacity = 0)
		: _a(nullptr)
		, _size(0)
		, _capacity(0)
	{ }
	void push_back(const T& date);
	int size()
	{
		return _size;
	}
	T& operator[](const int& i)
	{
		assert(i < _size);
		return _a[i];
	}
	~vector()
	{
		delete[] _a;
		_a = nullptr;
		_size = 0;
		_capacity = 0;
	}
private:
	T* _a;
	int _size;
	int _capacity;
};
template<class T>
void vector<T>::push_back(const T& date)
{
	if (_size == _capacity)
	{
		int newcapacity = _capacity == 0 ? 2 : _capacity * 2;
		T* tmp = new T[newcapacity];
		if (_a)
		{
			memcpy(tmp, _a, sizeof(T)*_size);
			delete[]_a;
		}
		_a = tmp;
		_capacity = newcapacity;
	}
	_a[_size] = date;
	_size++;
}
int main()
{
	vector<int>d_cpp_int;
	vector<double>d_cpp_double;
	d_cpp_int.push_back(1);
	d_cpp_int.push_back(2);
	d_cpp_int.push_back(3);
	d_cpp_double.push_back(1.1);
	for (int i = 0; i < d_cpp_int.size(); ++i)
	{
		
		//d_cpp_int.operator[](i) *=2;
		d_cpp_int[i] *= 2;//operator [] passes the return value so that the return object can be modified, so it is returned by reference. If there is no reference to return, the return value is the value of a temporary space (it is constant and cannot be changed)
	}
	for (int i = 0; i < d_cpp_int.size(); ++i)
	{
		cout << d_cpp_int[i] << " ";
	}
	cout << endl;


	system("pause");
	return 0;
}

Topics: C++