主页
  • 主页
  • 分类
  • 热文
  • 教程
  • 面试
  • 标签
C++

C++ 基础

C++ 主页
C++ 概述
C++ 环境
C++ 基本语法
C++ 注释
C++ 数据类型
C++ Hello, World
C++ 省略命名空间
C++ 数值类型
C++ 字符类型
C++ 布尔类型
C++ 变量
C++ 作用域
C++ 多个变量
C++ 输入输出基础
C++ 常量/文字
C++ 修饰符类型
C++ 存储类别
C++ 操作符
C++ 决策结构
C++ 循环结构
C++ foreach 循环
C++ 数字
C++ 数组
C++ 指针
C++ 枚举类型
C++ 引用变量
C++ 日期与时间
C++ 结构体
C++ 联合类型

C++ 字符串

C++ 字符串
C++ 字符串长度
C++ 字符串连接

C++ 函数

C++ 函数
C++ 多参数函数
C++ 递归
C++ return 语句
C++ 函数重载
C++ 函数重写

C++ 面向对象

C++ 面向对象
C++ 类和对象
C++ 多重继承
C++ 多层次继承
C++ 继承
C++ 重载
C++ 多态性
C++ 抽象
C++ 封装
C++ 接口

C++ 高级

C++ 文件和流
C++ 异常处理
C++ 动态内存
C++ 命名空间
C++ 模板
C++ 预处理器
C++ 信号量
C++ 多线程
C++ Web 编程
C++ 高级概念

基础

C++ 主页
C++ 概述
C++ 环境
C++ 基本语法
C++ 注释
C++ 数据类型
C++ Hello, World
C++ 省略命名空间
C++ 数值类型
C++ 字符类型
C++ 布尔类型
C++ 变量
C++ 作用域
C++ 多个变量
C++ 输入输出基础
C++ 常量/文字
C++ 修饰符类型
C++ 存储类别
C++ 操作符
C++ 决策结构
C++ 循环结构
C++ foreach 循环
C++ 数字
C++ 数组
C++ 指针
C++ 枚举类型
C++ 引用变量
C++ 日期与时间
C++ 结构体
C++ 联合类型

字符串

C++ 字符串
C++ 字符串长度
C++ 字符串连接

函数

C++ 函数
C++ 多参数函数
C++ 递归
C++ return 语句
C++ 函数重载
C++ 函数重写

面向对象

C++ 面向对象
C++ 类和对象
C++ 多重继承
C++ 多层次继承
C++ 继承
C++ 重载
C++ 多态性
C++ 抽象
C++ 封装
C++ 接口

高级

C++ 文件和流
C++ 异常处理
C++ 动态内存
C++ 命名空间
C++ 模板
C++ 预处理器
C++ 信号量
C++ 多线程
C++ Web 编程
C++ 高级概念

C++ 动态内存


上一章 下一章

对 C++ 中动态内存工作原理的良好理解对于成为一名优秀的 C++ 程序员至关重要。C++ 程序中的内存分为两部分:

  1. 栈 — 所有在函数内部声明的变量将占用栈上的内存。
  2. 堆 — 这是程序未使用的内存,可以在程序运行时动态分配。

很多时候,在定义变量时并不知道需要多少内存来存储特定信息,并且所需内存的大小可以在运行时确定。

你可以在堆上为给定类型的变量分配内存,使用 C++ 中的一个特殊操作符来返回分配的空间地址。这个操作符称为 new 操作符。

如果你不再需要动态分配的内存,可以使用 delete 操作符,它会取消由 new 操作符先前分配的内存。

new 和 delete 操作符

new 操作符用于动态分配内存的通用语法如下:

new 数据类型;

这里的 数据类型 可以是任何内置数据类型,包括数组或任何用户定义的数据类型,包括类或结构体。让我们从内置数据类型开始。例如,我们可以定义一个指向 double 类型的指针,然后请求在执行时分配内存。我们可以使用 new 操作符通过以下语句来实现这一点:

double* pvalue  = NULL; // 初始化为空指针的指针
pvalue  = new double;   // 请求变量的内存

如果内存没有成功分配,因为自由存储空间已经被用完。因此,检查 new 操作符是否返回空指针并采取适当措施是良好的做法:

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "错误: 内存不足。" << endl;
   exit(1);
}

尽管 C 中的 malloc() 函数仍然存在于 C++ 中,但建议避免使用 malloc() 函数。new 操作符的主要优点在于它不仅分配内存,还构造对象,这是 C++ 的主要目标之一。

当你觉得某个动态分配的变量不再需要时,你可以使用 delete 操作符释放其在自由存储区中占用的内存:

delete pvalue;        // 释放 pvalue 指向的内存

让我们将上述概念放入以下示例中,以展示 new 和 delete 如何工作:

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // 初始化为空指针的指针
   pvalue  = new double;   // 请求变量的内存
   
   *pvalue = 29494.99;     // 在分配的地址处存储值
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // 释放内存

   return 0;
}

如果我们编译并运行上述代码,这将产生以下结果:

Value of pvalue : 29495

动态数组内存分配

考虑你想要为一个字符数组分配内存,即长度为 20 个字符的字符串。使用与上述相同的语法,我们可以动态分配内存,如下所示:

char* pvalue  = NULL;         // 初始化为空指针的指针
pvalue  = new char[20];       // 请求变量的内存

要移除刚刚创建的数组,语句如下:

delete [] pvalue;             // 删除 pvalue 指向的数组

遵循 new 操作符的相似通用语法,你可以为多维数组分配内存如下:

double** pvalue  = NULL;      // 初始化为空指针的指针 
pvalue  = new double [3][4];  // 分配 3x4 数组的内存 

然而,释放多维数组内存的语法仍然相同:

delete [] pvalue;            // 删除 pvalue 指向的数组

对象的动态内存分配

对象与简单数据类型并无二致。例如,考虑以下代码,我们将使用对象数组来澄清这一概念:

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "构造函数调用!" << endl; 
      }
      ~Box() { 
         cout << "析构函数调用!" << endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // 删除数组

   return 0;
}

如果你分配一个包含四个 Box 对象的数组,简单的构造函数将被调用四次;同样地,在删除这些对象时,析构函数也将被调用相同次数。

如果我们编译并运行上述代码,这将产生以下结果:

构造函数调用!
构造函数调用!
构造函数调用!
构造函数调用!
析构函数调用!
析构函数调用!
析构函数调用!
析构函数调用!
上一章 下一章
阅读号二维码

关注阅读号

联系二维码

联系我们

© 2024 Yoagoa. All rights reserved.

粤ICP备18007391号

站点地图