Heap memory, stack memory and static memory in C++
There are three main types of Spaces in C++ : heap memory, stack memory, and static memory. Static memory is used to store global objects (objects defined outside of any function), local static objects, and static-like data members. Stack memory is used to store non-static objects defined within functions. The space occupied by objects in static and stack memory is automatically created and destroyed by the compiler. In addition, there is another type of memory that we allocate dynamically, which is heap memory. Objects in heap memory are created manually and need to be deleted manually, and forgetting to delete can cause a memory leak.
The following example is in the teacher hou jie’s C++ course, here I still through this example to illustrate the allocation of memory. We create two classes, Complex and String, defined as follows.
class Complex{
public:
Complex(int r=0.int v=0) :ri(r),vi(v){};
private:
int ri=0,vi=0;
}
class String{
public:
String(const char* str=0) {if (str){
s_data = new char[strlen(str)+1];
strcpy(s_data,str);
}else{
s_data = new char[1];
*s_data = '\ 0'; }} -String(a);private:
char * my_data;
}
Copy the code
Copy constructs, copy assignments, and destructors are not declared here primarily to illustrate the principle.
When we dynamically allocate a chunk of memory to our object in a function.
int main(a){
The first step is to create a specified size of memory in the heap, and then call operator new. In the new operator, the malloc function is called to allocate the space. The second step is to convert the returned space from void* to a pointer to the specified type, and the third step is to call the constructor of the class to initialize it. * /
Complex * ci = new Complex(a); String * si =new String(a); Complex * cm =new Complex[10];
String * sm = new String[10];
delete ci;
delete si;
delete [] cm;
delete [] sm;
/* The delete process is divided into two parts. The first step is to call the destructor. For example, there is no destructor for the built-in type int, and many objects of the same class have their own destructor. * /
}
Copy the code
The difference between allocating a dynamic array and a single object is as follows. For dynamic arrays, use new Typename [N] to allocate dynamic space, and delete with delete [] as well. So why do it? This is because when new [N] allocates at least N class-sized Spaces to the image, delete[] tells the compiler that we are deleting multiple Spaces, not just one. In the first step, delete calls the destructor once, while delete[] calls the destructor N times.
When we use delete and delete[] to handle Pointers to Complex objects, there is no difference, because there is no destructor for int numbers, so we still successfully free memory. This is not the case for String. If we use DELETE, the destructor is called once and the rest is not called. Here is the destructor for String.
String::~String() {delete [] s_data;
}
Copy the code
In the destructor we delete the s_data pointer, freeing the memory to which it refers.
So if we use delete sm instead of delete [] sm, the destructor is called only once in the whole process, and the remaining 9 s_data Pointers to the heap are not freed correctly.Delete and delete[] are used incorrectly because the memory of the pointer to delete has not been freedPointers to other heap memory are not released correctly.
After listening to miss Hou’s class, I thought about it and wrote the following code.
using namespace std;
class Node{
public:
int i=1;
~Node(){
cout<<"dx"<<endl; }};class s{
public:
s(){
Node fnode;
n = &fnode;
}
Node* n;
};
int main(a){
s* ps = new s[10];
cout<<ps->n->i;
}
/*result=
dx
dx
dx
dx
dx
dx
dx
dx
dx
dx
1
*/
Copy the code
In my opinion, the last piece of code should have gone wrong because I pointed n to a local variable, but the result was something like the one above. After searching for information on the Internet, I will explain the whole process according to my own understanding.
S * ps = new S [10]; s* ps = new S [10]; s* ps = new S [10]; When fNode leaves the scope of the constructor, its destructor is called directly.
Why can we access I through N when the destructor is called?
At this point we n points to the stack memory in a space, for example, you obtained a space in the stack memory through n, n is the key that you right now, space is your house, before you visit again, the compiler can to cover you referred to in the space, it can replace all the furniture inside the house, But if it doesn’t cover the space, you can re-enter the house illegally with the same furniture as when you left. It is perfectly possible for C++ to zero out all the stack space you use, but it is not necessary because doing so would take extra time.
C++ allows you to do this, but that doesn’t make it right, and this undefined behavior is the most dangerous of all.
Reference sources: 1, Hou Jie object-oriented c + + high-level programming www.bilibili.com/video/BV14s…
2, Stackoverflow
Stackoverflow.com/questions/6…