Memory distribution malloc/calloc/realloc/free/new/delete, memory leak, string template, shallow copy and deep copy, and the implementation of simulated string class

Posted by jkatcherny on Tue, 04 Jan 2022 22:59:37 +0100

Memory distribution

1, Dynamic memory management in C language: malloc/calloc/realloc and free

1.malloc:

Obtain the memory space of the specified byte from the heap. The function declaration: void *malloc (int n);

If the function is executed successfully, malloc returns the first address of the obtained memory space; If the function fails, the return value is NULL.

The heap memory obtained by malloc function must be initialized with memset function.

char *str = (char*) malloc(100);
assert(str != nullptr);

2.calloc:

Similar to malloc, the function declaration is void *calloc(int n, int size)// Application space = n*size

After successful execution, obtain the byte space of size * n from the heap and return the first address of the space. The execution failed and the function returned NULL.

The memory space obtained by the calloc function is initialized, and its contents are all 0.

3.realloc

The functions are richer than the first two, which can realize memory allocation and memory release. Function declaration: void * realloc(void * p,int n);

Where, the pointer p must be a pointer to the heap memory space, that is, a pointer to the space allocated by the malloc function, calloc function or realloc function.

The realloc function changes the size of the memory block pointed to by the pointer p to n bytes. If n < or = the size of the space pointed to before P, the original state remains unchanged.

If n > the size of the space previously pointed to by p, the system will reallocate a memory space of N from the heap for p

At the same time, the contents of the original pointing space are copied to the new memory space in turn, and the space pointed to before p is released. The space allocated by the relloc function is also uninitialized.

4.alloca

Request memory on the stack. When the program is out of the stack, it will automatically release memory. However, it should be noted that alloca is not portable, and it is difficult to implement on a machine without a traditional stack. Alloca should not be used in programs that must be widely transplanted. C99 supports variable length arrays (Vlas), which can be used to replace alloca.

5.free    void free (void * p); Free the space on the heap indicated by void pointer P. No return value

free(p); 
p = nullptr;

6.memset   void * memset (void * p, int c, int n) ;

Return value: returns a void type pointer to the storage area p.

For the n bytes of the first address of the void pointer p, set each byte to c.

malloc/calloc/realloc differences:

Similarities:

          1. They all apply for space from the heap
          2. The return value needs to be null
          3. User free release is required
          4. The return value type is the same (void *)
          5. Both require type conversion
          6. Like the underlying implementation, it is necessary to open up redundant space to maintain the application space

 

difference:
         1. Different function names and parameter types.
         2.calloc will initialize the application space and initialize it to 0, while the other two will not.
         3. The space requested by malloc must be initialized with memset
         4.realloc is to adjust the existing space. When the first parameter is passed in NULL, it is the same as malloc
2, C + + memory management mode (new, delete)

Dynamic memory management through new and delete operators to apply for and release continuous space.

1. When new applies for space, it will call the constructor. When delete frees up space, it will call the destructor, but malloc and free will not.

2.operator new and operator delete

It is a global function provided by the system. New and delete release space by calling the operator new and noperator delete global functions at the bottom.

3. The difference between malloc / free and new/delete

Common ground: heap application, manual release

Differences: 1 Malloc and free are functions, and new and delete are operators

               2. The space requested by malloc will not be initialized, but new can be initialized
3. When malloc applies for space, it needs to manually calculate the space size and pass it. new only needs to follow the space type
4. The return value of malloc is void *, which must be forcibly rotated when used. New is not required, because new is followed by the type of space
5. When malloc fails to apply for space, it returns NULL, so it must be NULL when used. New does not need to, but new needs to catch exceptions
6. When applying for custom type objects, malloc/free will only open up the space and will not call the constructor and destructor, while new will call the constructor to initialize the object after applying for the space, and delete will call the destructor to clean up the resources in the space before releasing the space
7. The efficiency of new/delete is slightly lower than that of malloc and free, because the underlying layer of new/delete encapsulates malloc/free

4. Implementation principle of new and delete

Built in type: if you are applying for a built-in type space, new and malloc, delete and free are basically similar,

The difference is that new/delete requests and releases the space of a single element, new [] and delete [] apply for continuous space, and new throws an exception when the space application fails, and malloc returns NULL

Principle of new
                 1. Call the operator new function to request space
                 2. Execute the constructor on the requested space to complete the construction of the object
Principle of delete
                 1. Execute the destructor in space to clean up the resources in the object

                 2. Call the operator delete function to free up the space of the object
Principle of new T[N]
                 1. Call the operator new [] function, and actually call the operator new function in operator new [] to complete the application of N object spaces
                 2. Execute the constructor N times on the requested space
Principle of delete []
                 1. Execute the destructor N times on the released object space to clean up the resources in N objects
                 2. Call operator delete[] to release the space, and actually call operator delete in operator delete[] to release the space.

5. Singleton mode: a class can only create one object, and the instance is shared by all program modules.

Hungry man mode: the program is loaded and initialized at the beginning, resulting in a very slow program.

Advantages: simple. Disadvantages: the process starts slowly.

Lazy mode: don't load it at the beginning, and load it when you need it.

Advantage: when you first use an instance object, you create it. The process starts without load. The startup sequence of multiple single instance instances is freely controlled.
Disadvantages: complex

6. Memory leakage

What is a memory leak?

Memory leakage refers to the situation that the program does not release resources and no longer uses memory due to negligence or error. Memory leak means that after an application allocates a certain section of memory, it loses control of the memory due to design errors, resulting in a waste of memory.

Memory leak classification:

Heap memory leak:

Heap memory refers to a piece of memory allocated through malloc/calloc/realloc/new during program execution. After it is used up, it must be released through free/delete. If it is not released, this part of space cannot be used later, and Heap Leak will be generated.

System resource leakage:

The program uses the resources allocated by the system, such as sockets, file descriptors, pipes, etc. without using the corresponding functions, resulting in a waste of system resources, seriously reducing the system efficiency and unstable system execution.

How to avoid memory leakage?

1. Preventive in advance. Such as smart pointer, etc. (managed by RAII idea or smart pointer)

2. Error checking afterwards. Such as leak detection tools.

Designing a class can only create objects on the heap. (the constructor is privatized, providing a static member function in which the creation of heap objects is completed)

class HeapOnly    
{     
public:     
    static HeapOnly* CreateObject()  
    {      
        return new HeapOnly;    
    }
private:    
    HeapOnly() {}
    
    // C++98
    // 1. Only declaration, not realization.
    // 2. Declared private
    HeapOnly(const HeapOnly&);
    // or 
    // C++11    
    HeapOnly(const HeapOnly&) = delete;
};

When designing a class, you can only create objects on the stack.

class StackOnly    
{    
public:    
    static StackOnly CreateObject()  
    {      
        return StackOnly();   
    }
private:
    StackOnly()  {}
}; 

 

Three. Template junior

1. Function template and its instantiation

template<typename T1, typename T2,......,typename Tn>

Return value type function name (parameter list) {}

Implicit instantiation: compiler automatically infers types

Display instantiation: use < >

template<typename T>
void Swap( T& left,  T& right)
{
    T temp = left;
    left = right;
    right = temp;
}

Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters

Explicit instantiation: specify the actual type of the template parameter in < > after the function name (if it does not match, implicit type conversion will be performed)

Matching rules for 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 the non template function.

          2. For non template functions and function templates with the same name, if other conditions are the same, non template functions will be called preferentially during transfer. 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

2. Class template and its instantiation:

template<class T1, class T2, ..., class Tn>

class Class template name

{

// Intra class member definition

};

Priority principle: choose who is more like me.

4, STL (an important part of C + + standard library, including software framework of data structure and algorithm)

1. Six components of STL

 2. Common interfaces of string class

string()                    Construct empty string Class object, empty string
string(const char* s)       use C-sting Construct class object
string(size_t n,char c)     string Class object contains n Characters c
string(const string&s)      copy constructor  
string(const string&s,size_t n)   use s Medium n Characters to construct a new string Class object

3. Capacity interface of string class object

size_t size() const                Returns the valid character length of a string
size_t length() const              Returns the valid character length of a string
size_t capacity()const             Returns the total size of the space
bool empty()const                  If the detection string is released as an empty string, it is returned true,Otherwise return false
void clear()                       Clear valid characters
void resize (size_t n, char c)     Change the number of valid characters to n Characters for extra space c fill
void resize (size_t n)             Change the number of valid characters to n The extra space is filled with 0
void reserve (size_t res_arg=0)    Reserve space for string

4. Access operation of string class object

char& operator[] ( size_t pos )       return pos The character of the position, const string Class object call
const char& operator[] ( size_t pos ) const return pos Character of position, not const string Class object call

5. Modification of string class object

void push_back(char c)                    Insert character after string c
string& append (const char* s);           Append a string after the string
string& operator+=(const string& str)     Append string after string str
string& operator+=(const char* s)         Append after string C Number string
string& operator+=(char c)                Append character after string c
const char* c_str( )const                 return C Format string
size_t find (char c, size_t pos = 0)const
 From string pos Position starts looking back for characters c,Returns the position of the character in a string
size_t rfind(char c, size_t pos = npos)
From string pos Position start find character forward c,Returns the position of the character in a string
string substr(size_t pos = 0, size_t n = npos)const
 stay str Zhongcong pos Position start, intercept n Characters, and then return it

 6. Use the string class to flip the string: (the code is as follows:)

#include <iostream>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
//Flip string
class Solution{
public:
	string reverseString(string s){
		if (s.empty())//First, judge whether the string is empty
		{
			return s;
		}
		size_t start = 0;//Defines the beginning of the valid length of a string
		size_t end = s.size() - 1;//Define the tail of the effective length of a string, using size-1
		while (start < end){
			swap(s[start], s[end]);//String exchange
			++start;//Go back from the starting position
			--end;//Go from the back
		}
		return s;
	}
};
int main(){	
	string s = "0123456789";
	cout << Solution().reverseString(s) << endl;
	system("pause");
	return 0;
}

 7. Find the character that appears only once for the first time in the string: (the code is as follows:)

#include <iostream>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
//Flip string
class Solution{
public:
	int firstUniqchar(string s){
		//Count the number of occurrences of each character
		int count[256] = { 0 };//Define a counter
		int size = s.size();//Define a valid character length
		for (int i = 0; i < size; ++i){
			count[s[i]] += 1;//s[i] indicates the count of characters corresponding to ASCll plus 1
			//Look for characters that appear only once from front to back in character order		
			}
		for (int i = 0; i < size; ++i){
				if (1 == count[s[i]]){//Traverse the character whose counter is 1 and return i
					return i;//Find the first character that appears only once
					//cout << s[i] << endl;// Print out all characters that appear only once
				}			
		}
		return -1;		
	}
};
int main(){	
	string s = "xx1223456789";
	cout << Solution().firstUniqchar (s) << endl;
	system("pause");
	return 0;
}

 8. Length of the last word in the string:

int main(){	
	string line;
	while (getline(cin, line)){
		size_t pos = line.rfind(' ');//rfind finds the character from the pos position and returns the position of the character
		cout << line.size() - pos - 1 << endl;//size the entire character length - pos, followed by the last word - 1, minus the length of the space 1
	}
	system("pause");
	return 0;
}

 9. Verify that a string is a palindrome:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
int main(){	
	string s;//Define STL string
	cin >> s;//cin input string
	int i = 0;
	int j = s.size() - 1;//Define string length
	for ( i , j; i < j; i++, j--){
		if (s[i] != s[j]){//Use the double pointer to scan from both sides to the middle to judge whether the characters corresponding to the subscript are equal
			break;
		}
	}
	if (i<j){
		cout << "No" << endl;
	}
	else{
		cout << "yes" << endl;
	}
	system("pause");
	return 0;
}

s.size () is the length of the string, starting with 1. s.size () - 1 is the subscript of the last character, starting from 0

The find/rfind function can pass three things:

1. Characters

2. String

3. Character container

find is from the front and rfind is from the back.

10. Light copy and deep copy:

Shallow copy: also known as bit copy, it means that the compiler only copies the values in the object. If resources are managed in the object, multiple objects will share the same resource. When an object is destroyed, it will be released, while other objects do not know it and think it is still valid. When access continues, an access error will occur.

Deep copy: to solve the problem of shallow copy, each object is allocated resources independently to ensure that multiple objects will not be released for multiple times due to shared resources, resulting in program crash. Copy constructors, assignment operator overloads, and destructors must be explicitly given.

Copy on write: on the basis of shallow copy, increase the reference count method, record the number of resources used, increase the object use, and add 1 to the count. When the object is destroyed, the count will be reduced by 1, and then check whether the resource needs to be released. If the count is 1, it indicates that it is the last object, it will be released, otherwise it cannot be released.

Simulated implementation of string class:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cassert>
#include <vector>
using namespace std;
//Simulate the implementation of string class
class String{
public:
	String(const char* str = ""){//Constructor
		if (nullptr == str){//1. First judge whether str is empty
			assert(false);//Asserts that if the program executes incorrectly, it terminates
			return;
		}
		_size = strlen(str);//Define str length as_ size
		_capacity = _size;//Definition_ Size is the size of the space_ capacity
		_str = new char[_capacity + 1];//New apply for a new space
		strcpy(_str, str);//String copy copy
	}
	String(const String& s)//copy constructor 
		:_str(new char[s._capacity + 1])//Initialization list
		, _size(s._size)
		, _capacity(s._capacity)
	{
		strcpy(_str, s._str);
	}
	String& operator=(const String& s){//Operator overloading 
		if (this != &s){//Determine whether this is equal to the s reference
			char* pstr = new char[s._capacity + 1];//New application space
			strcpy(pstr, s._str);//Copy data

			delete _str;//Before release_ str
			_str = pstr;//Assign the newly requested space to_ str
			_size = s._size;
			_capacity = s._capacity;
		}
		return *this;
	}
	~String(){//Destructor, releasing resources
		if (_str){
			delete[] _str;
			_str = nullptr;//str null			
		}
	}
	//Modification of string class
	void PushBack(char c){//Insert str, pushback
		if (_size == _capacity){//Determine whether size and space are equal
			//reserve(_capacity * 2);// 2X space expansion
			_str[_size++] = c;
			_str[_size] = '\0';
		}
	}
		void Append(size_t n, char c){//Add str string,
			for (size_t i = 0; i < n; ++i){
				PushBack(c);
			}
		}
		String& operator+=(char c){//Operator overloading+=
			PushBack(c);
			return *this;
		}
		//Job implementation
		void Append(const char* str);
		String& operator+=(const char* str);
		void Clear(){//Clear string
			_size = 0;
			_str[_size] = '\0';
		}
		void Swap(String& s){//String exchange
			swap(_str, s._str);
			swap(_size, s._size);
			swap(_capacity, s._capacity);
		}
		const char* C_str()const//Returns a C-string
		{
			return _str;
		}
		size_t Size()const
		{
			return _size;
		}
		size_t Capacity()const
		{
			return _capacity;
		}
		bool Empty()const
		{
			return 0 == _size;
		}
		size_t Find(char c, size_t pos = 0)const;//Returns the first occurrence of the character c in a string
		size_t Find(const char* s, size_t pos = 0)const;//Returns the first occurrence of the string s in a string
		String Substr(size_t pos, size_t n);//Intercept n characters of string starting from pos position
		String& Insert(size_t pos, char c);//Insert the character c in the pos position and return the character position
		String& Insert(size_t pos, const char* str);//Inserts the string str at the pos position and returns the string position
		String& Erase(size_t pos, size_t len);//Deletes the element at the pos position and returns the next position of the element	
private:
	friend ostream& operator<<(ostream& _cout, const String& s);//< < operator overload, friend class
private:
	char* _str;
	size_t _capacity;
	size_t _size;
};
ostream& operator<<(ostream& _cout, const String& s)//< < operator overload
{
	cout << s._str;
	return _cout;
}
int main(){	
	string s1;//Define STL string
	string s2("hello bit");
	string s3(s2);
	s1 = s3;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	system("pause");
	return 0;
}

Topics: C++ string STL