动态内存
基本概念
了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:
栈:在函数内部声明的所有变量都将占用栈内存。
堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。
new 和 delete 运算符
new 运算符:
给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。
delete 运算符:
如果您不再需要动态分配的内存空间,删除之前由 new 运算符分配的内存。
在任何时候,当您觉得某个已经动态分配内存的变量不再需要使用时,您可以使用 delete 操作符释放它所占用的内存,如下所示:
delete pvalue; // 释放 pvalue 所指向的内存
Code
本例代码,显示用new关键字动态分配了一下内存并且赋值,然后再判断了一下分配的内存地址是否为0,为0则表示oom,最后再delete并释放内存。
#include <iostream>
using namespace std;
int main()
{
//------动态分配内存(实际上三行代码实现了一行代码的功能:double pvalue = 11.99;)----------
double* pvalue = NULL; // 初始化为 null 的指针
pvalue = new double; // 为变量请求内存
cout << "pvalue address: " << pvalue << endl;
*pvalue = 11.99; // 在分配的地址赋值
cout << "赋值之后 Value of pvalue : " << *pvalue << endl;
//------ 判断分配的地址是否为空 ----------
double* pvalueif = NULL;
//分析:
//if(0038D3A0) ==> true ,!true == false,则正常
//若是if(0) == > false , !false == true ,那么则oom
if (!(pvalueif = new double))
{
cout << "error: out of memory." << endl;
exit(1);
}
else if (pvalueif = new double) {
cout << "yes: 正常" << endl;
}
delete pvalue; // 释放内存
getchar();
return 0;
}
输出:
pvalue address: 0048D3A0
赋值之后 Value of pvalue : 11.99
yes: 正常
关于malloc()
malloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。
数组的动态内存分配
1.创建一维就是int * array;
,二维就是int ** array
,三维就是int *** array
;
2.本例代码流程是,定义,开辟空间,赋值,打印。
一维
//一维数组
void one_dimmision() {
//int[3] array = { 1,2,3 };
int * array;
int i = 3;
//申请内存
array = new int[i];
//赋值
for (int o = 0; o < i; o++)
{
array[o] = o;
}
//打印
//int size = sizeof(array) / sizeof(array[0]);//动态数组不能用这种方式获取其长度
//打印
for (int i = 0; i < 3; i++)
{
cout << array[i] << ",";
}
//删除该数组内存
delete[]array;
}
二维
//二维数组
void two_dimmision() {
int ** array;//二维数组指针,二维就是2个*
int i = 3,j=4;//3行4列
array = new int*[i];
//开辟内存
for (int o = 0; o < i; o++){
array[o] = new int[j];//数组每个元素又是一个数组
}
//赋值
for (int m = 0; m < i; m++)
{
for (int n = 0; n < j;n++) {
array[m][n] = 10 * m + n;
//打印
if (n == j -1) {
cout << array[m][n] << "," << endl;
}
else {
cout << array[m][n] << ",";
}
}
}
//删除
for (int o = 0; o < i; o++)
{
delete [] array[o];//delete 类型 元素
}
}
输出:
//0, 1, 2, 3,
//10, 11, 12, 13,
//20, 21, 22, 23,
三维
//三维数组
void threee_dimmision() {
int *** array;
int i = 3, j=4, k=5;
array = new int **[i];
//开辟内存 1维
for (int o = 0; o < i; o++)
{
array[o] = new int *[j];//数组每个元素又是一个二维数组
}
//开辟内存 2维
for (int m = 0; m < i; m++)
{
for (int n = 0; n < j;n++ ) {
array[m][n] = new int[k];//开辟内存三维,数组每个元素又是一个一维数组
//赋值
for (int o = 0; o < k; o++)
{
array[m][n][o] = 100 * m + (10 * n) + o;
//打印
//删除该数组内存
//delete[] array[m];
if (o == k - 1) {
cout << array[m][n][o] << "," << endl;
}
else {
cout << array[m][n][o] << ",";
}
}
cout << endl;
}
cout << endl;
}
}
输出:
//20, 21, 22, 23, 24,
//30, 31, 32, 33, 34,
//100, 101, 102, 103, 104,
//110, 111, 112, 113, 114,
//120, 121, 122, 123, 124,
//130, 131, 132, 133, 134,
//200, 201, 202, 203, 204,
//210, 211, 212, 213, 214,
//220, 221, 222, 223, 224,
//230, 231, 232, 233, 234,
对象数组的动态内存分配
注意这儿是对象数组:
Box* myBoxArray = new Box[4];
另外注意:
//Box myBoxArray = new Box; //错误写法
#include <iostream>
using namespace std;
class Box
{
public:
Box() {
cout << "调用构造函数!" << endl;
}
~Box() {
cout << "调用析构函数!" << endl;
}
};
int main()
{
Box* myBoxArray = new Box[4];
//Box myBoxArray = new Box; //错误写法
delete[] myBoxArray; // 删除数组
return 0;
}
模板
模板就是泛型。分为模板方法,模板类,我个人比较习惯称其为泛型方法,泛型类。
泛型方法
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T const& Max(T const& a, T const& b)
{
return a < b ? b : a;
}
int main()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
string s1 = "Hello";
string s2 = "World";
cout << "Max(s1, s2): " << Max(s1, s2) << endl;
getchar();
return 0;
}
核心代码
template <typename T>//泛型声明
T const& Max(T const& a, T const& b)
{
return a < b ? b : a;
}
泛型类
#include <iostream>
#include <string>
using namespace std;
template <class T>
class A {
public:
void sayHello(T const&);
T get();
};
template <class T>
void A<T> :: sayHello(T const& t){
cout << "say :" << t << endl;
}
template <class T>
T A<T>::get() {
cout << ": : get : :" << endl;
return NULL;
}
int main()
{
A<int> a;
a.get();
a.sayHello(666);
getchar();
return 0;
}
总结
1.template //泛型方法的声明
2.template //泛型类的声明
3.泛型参数,一般定义为T const&,但并不是必须的,这个在附录里有讲到。
4.不仅仅在声明的时候需要使用声明语句,在我们实现泛型方法的时候也需要用到泛型声明语句template 。
C++ 异常处理
try、catch、throw
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
- catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块
抛出异常
除0异常
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
捕获异常
catch 块跟在 try 块后面,用于捕获异常。您可以指定想要捕捉的异常类型,这是由 catch 关键字后的括号内的异常声明决定的。
try
{
// 保护代码
}catch( ExceptionName e )
{
// 处理 ExceptionName 异常的代码
}
如果想让 catch 块能够处理 try 块抛出的任何类型的异常,则必须在异常声明的括号内使用省略号 …,如下所示:
try
{
// 保护代码
}catch(...)
{
// 能处理任何异常的代码
}
Code
抛出一个除以零的异常,并在 catch 块中捕获该异常。
#include <iostream>
using namespace std;
double division(int a, int b)
{
if (b == 0)
{
throw "Division by zero condition!";
}
return (a / b);
}
int main()
{
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
}
catch (const char* msg) {//catch块跟抛出throw除的东西类型有对应,这里我们抛的一个字符串,它是const char*类型
cerr << msg << endl;
}
getchar();
return 0;
}
C++有哪些种类的异常
参考:http://www.runoob.com/cplusplus/cpp-exceptions-handling.html
自定义异常
#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
};
int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
//其他的错误
}
}
附录
int const& 和 const int&有什么区别?
int const&表示此引用所代表的int类型变量无法使用此引用修改.
const int&表示此引用所代表的是const int类型变量,同样也无法用此引用修改.
两者的区别是:
int const&所代表的变量可以是int 和 const int .
const int&所代表的变量仅可以是 const int .
Thanks
http://www.runoob.com/cplusplus/cpp-exceptions-handling.html
本文Demo:https://github.com/zj614android/c-c-/tree/master/Lis8