C++ 内存管理(memory Management) part1
来源:互联网 发布:excel文档修复软件 编辑:程序博客网 时间:2024/05/27 03:26
首先说说constructors(建构子)这个类的特殊的成员函数。
当一个类的instance被创建时, 会呼叫建构子以对对象的数据初始化。
例如如下例:
声明一个整数的类:
#include <iostream>using namespace std;class Integer { private: int val; public: Integer() { val = 0; cout << "default constructor" << endl; }}; //分号不能少int main() { Integer i; return 0;}
运行结果为:
不难发现, 上述主程序中子调用了默认建构子。
当我们创建an array of objects的时候, 默认建构子会逐一调用(必须有默认建构子, 才可以创建an array of objects)。
#include <iostream>using namespace std;class Integer { private: int val; public: Integer() { val = 0; cout << "default constructor" << endl; }}; //分号不能少int main() { Integer arr[3]; return 0;}
程序运行结果为:
当在一个类中使用了另一个类声明的对象作为其成员变量, 此时城建这个类的对象的时候, 也会调用内部那个嵌入类的constructor, 以便对其初始化。
例:
#include <iostream>using namespace std;class Integer { private: int val; public: Integer() { val = 0; cout << "Integer default constructor" << endl; }}; //分号不能少class IntegerWrapper { private: Integer val; public: IntegerWrapper() { cout << "IntegerWrapper default constructor" << endl; }};int main() { IntegerWrapper q; return 0;}
运行结果为:
Constructor 也可以有参数, 但是此时该建构子不是默认的construtor, 以便传递参数更好地初始化。 此时, 我们必须定义(写明)默认的建构子。 否则默认的建构子 not available。 如果不写明默认建构子, 一个缺点就是无法什么 array of objects without initializing了。
例如, 下面的两个程序是错误的:
#include <iostream>using namespace std;class Integer { private: int val; public: Integer(int v) { val = v; cout << "Integer default constructor" << endl; }}; //分号不能少int main() { Integer i(3);//ok Integer j;// error return 0;}
上述代码会出错, 再例如:
#include <iostream>using namespace std;class Integer { private: int val; public: Integer(int v) { val = v; }}; //分号不能少int main() { Integer a[] = {Integer(2), Integer(5)};//ok, initializing Integer b[2];// error, without initializing return 0;}
下面修改如上的代码, 两种办法, (1)单独写一个默认的建构子(默认的就是没有参数的)
(2)采用函数的default 用一个建构子代表两个建构子(一个有参数, 一个是无参数的默认建构子):
#include <iostream>using namespace std;class Integer { private: int val; public: Integer(int v) { val = v; } Integer() { val = 0; }}; //分号不能少int main() { Integer a[] = {Integer(2), Integer(5)};//ok, initializing Integer b[2];//okay return 0;}
上述的代码是correct的。
this 指针
当一个method的参数的名字和类的一个field同名的时候, 如何去区分呢, 这就用到了this指针。 this指向当前调用这个方法的对象的位置。
例如:
class Integer { private: int val; public: Integer(int val = 0) { //default parameter this -> val = val; } void setVal(int val) { this -> val = val; }}; //分号不能少
接下来, 说说Scoping and Memory
每当我们声明一个新的变量的时候(int x), 编译器就会给这个变量x 分配(allocate)一个内存。 当这个变量go out of scope 的时候, 这个内存就会被释放掉(be freed up), 以便这个内存位置可以分配给其他变量。
例如:
int main() { if (true) { int x = 5; //declare a variable, allocate memory } // x now out of scope, memory it used to occupy can be reused}
一句话, 当一个variable goes out of scope, that memory is no longer guaranteed to store the variables value。
在举一个例子:
int main() { int *p; if (true) { int x; p = &x; } cout << *p << endl; // ???, x is out of scope, so it will get wrong answer return 0;}
上个例子会出错。
具体分析内存分配如下面几幅图:
上图中, 最后一幅图不难看出, 变量x goes out of scope, 所以该内存(用于存储5的memory)被释放掉了。 也就是说, 此时指针p变成了一个dangling pointer(也就是说指针指向的memory的contents 是未定义的(undefined))。
A problematic Task
Implement a function which returns a pointer to some memory containing the integer 5.
下面的实现的函数是incorrect的,原因是变量x 是在function scope 中, 该函数返回的时候, x 就会go out of scope。 所以此时返回的指针就变成了一个dangling pointer。
int *getPtrToFive() { int x = 5; return &x;}int main() { int *p = getPtrToFive(); cout << *p << endl; //??}
上述函数的实现方法是不正确的。 走出这个dilemma的方法就是我们动态的分配内存。这种动态分配的内存会一直remian 下去直到我们manually de-allocate it。
动态分配内存用到了new operator,此时返回一个pointer 指向the newly allocated memory. 如下句:
int *x = new int;
NOTE:
——如果使用 int x; 分配的内存区域在the stack (栈)中
——如果使用 new int; 分配的内存区域在the heap (堆)中。
要释放由 new operator 分配在heap 中的内存, 必须使用delete operator 手动释放的。 (这两个运算符需要配套使用, 使用完毕后, 用delete释放动态内存)。
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { int *p = getPtrToFive(); //动态分配内存的时候对指针的初始化 cout << *p << endl; //5 delete p;}
注意, 如果使用完后, 不用delete 去deallocate由new 分配的动态内存, 那么我们编写的application 就会waste memory。
如下例:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { for (int i = 0; i < 3; ++i) { p = getPtrToFive(); cout << *p << endl; }}
具体分析如下:
上述的程序错误的原因在于没有deallocate 分配的动态内存。
再比如, 下面的例子, 虽然delete了, 但是只是deallocate 最后一次分配的动态、内存:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { for (int i = 0; i < 3; ++i) { p = getPtrToFive(); cout << *p << endl; } delete p; }
上述的语句时不正确的, 因为它导致了memory leak(内存泄露)。 要想修正这个错误, 从而避免内存泄露, 把delete的语句放在loop内:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { for (int i = 0; i < 3; ++i) { p = getPtrToFive(); cout << *p << endl; delete p; } return 0;}
注意, 删除heap中的动态内存之后, 就不要再使用分配的内存了:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { int *p = getPtrToFive(); //动态分配内存的时候对指针的初始化 delete p; cout << *p; // error}
必须在使用之后, 不再需要了, 才删除:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { int *p = getPtrToFive(); //动态分配内存的时候对指针的初始化 cout << *p << endl; //5 delete p; return 0;}
注意, 同一个内存空间删除两次:
int *getPtrToFive() { int *x = new int; *x = 5; return x;}int main() { int *p = getPtrToFive(); //动态分配内存的时候对指针的初始化 cout << *p << endl; //5 delete p; delete p; // error return 0;}
只有用new 分配的动态内存才可以使用delete operator:
int main() { int x = 5; int *xPtr = &x; cout << *xPtr << endl; delete xPtr; //error return 0;}
上面是错误的, 应该使用:
int main() { int x = 5; int *xPtr = &x; cout << *xPtr << endl;}
Allocating Arrays
在stack 中声明数组时(分配内存), 我们必须指定数组的size 为常量, 不能为变量。也就是说:
int arr[SIZE];// size 必须为常量
例如, 下面的语句时错误的:
int numItems;cout << "How many items?";cin >> numItems;int arr[numItems]; // not allowed
要想实现动态的分配数组的内存, 必须使用 new [] , 这时候, 数组可以有variable size, 例如:
int numItems;cout << "How many items?";cin >> numItems;int *arr= new int[numItems];
具体分析如下:
删除动态数组的内存, 使用的是 delete[], 如下:
int numItems;cout << "How many items?";cin >> numItems;int *arr= new int[numItems];delete[] arr;
下面举个例子:
#include <iostream>using namespace std;int main() { int numItems; cout << "How many items?"; cin >> numItems; int *arr = new int[numItems]; for (int i = 0; i < numItems; ++i) { cout << "Enter item" << i << ":"; cin >> arr[i]; } for (int i = 0; i < numItems; ++i) { cout << arr[i] << endl; } delete[] arr; return 0;}
运行结果如下:
- C++ 内存管理(memory Management) part1
- ##Memory Management (内存管理)
- 实际内存管理(Practical Memory Management)
- 内存管理策略(memory Management Policy)
- Memory management in C programs( C内存管理 )
- Android Memory Management(内存管理)
- C的存储类,链接与内存管理(Storage Class, Linkage, Memory Management)
- C#自动化的内存管理(Automatic memory management)
- C#自动化的内存管理(Automatic memory management)
- IOS内存管理策略(Memory Management Policy)
- MMU(Memory Management Unit,内存管理单元)的作用
- Android内存管理(Memory Management), OutOfMemoryError Note
- IOS内存管理策略(Memory Management Policy)
- Memory Management(5)DXE 内存管理流程
- 内存管理 Memory Management for Android Apps
- C++ Memory Management C++ 内存管理
- Memory Management Policy(内存管理政策)
- Linux内存管理Linux Memory Management Notes
- hdu-4656-So Easy!-递推式+矩阵优化
- 关于掉电保存数据的思考
- CAS SSO 工作机制(每一步请求详述)
- OpenCV学习笔记7 OpenCV核心模块与核心功能Core Module & Core Functionality(六)
- 编程语言类型划分
- C++ 内存管理(memory Management) part1
- Aurora中Problems running LaTex的解决方案 && Aurora2.x注册机
- JAVA正则表达式语法大全
- Type mismatch: cannot convert from Enumeration<String> to Enumeration<Object>
- Linux中fork()函数详解
- postpresql Jdbc java连接
- CodeForces 26C Parquet 构造题
- Graphs part1
- leetcode: Sqrt(x)