耗尽内存
尽管现代机器的内存容量越来越大,但是自由存储区总有可能被耗尽。如果程序用完了所有可用的内存,new
表达式就有可能失败。如果 new 表达式无法获取需要的内存空间,系统将抛出名为 bad_alloc 的异常。我们将在第 6.13
节介绍如何抛出异常。
撤销动态创建的对象
动态创建的对象用完后,程序员必须显式地将该对象占用的内存返回给自由存储区。C++ 提供了 delete
表达式释放指针所指向的地址空间。
delete pi;
frees the memory associated with the int object
addressed by pi.
该命令释放 pi 指向的 int 型对象所占用的内存空间。
|
如果指针指向不是用 new 分配的内存地址,则在该指针上使用 delete
是不合法的。
|
C++ 没有明确定义如何释放指向不是用 new 分配的内存地址的指针。下面提供了一些安全的和不安全的
delete expressions 表达式。
int i;
int *pi = &i;
string str = "dwarves";
double *pd = new double(33);
delete str; // error: str is not a dynamic object
delete pi; // error: pi refers to a local
delete pd; // ok
值得注意的是:编译器可能会拒绝编译 str 的 delete 语句。编译器知道
str
并不是一个指针,因此会在编译时就能检查出这个错误。第二个错误则比较隐蔽:通常来说,编译器不能断定一个指针指向什么类型的对象,因此尽管这个语句是错误的,但在大部分编译器上仍能通过。
零值指针的删除
如果指针的值为 0,则在其上做 delete 操作是合法的,但这样做没有任何意义:
int *ip = 0;
delete ip; // ok: always ok to delete a pointer that is equal to 0
C++ 保证:删除 0 值的指针是安全的。
在 delete 之后,重设指针的值
执行语句
delete p;
后,p 变成没有定义。在很多机器上,尽管 p
没有定义,但仍然存放了它之前所指向对象的地址,然而 p 所指向的内存已经被释放,因此 p 不再有效。
删除指针后,该指针变成悬垂指针。悬垂指针指向曾经存放对象的内存,但该对象已经不再存在了。悬垂指针往往导致程序错误,而且很难检测出来。
|
一旦删除了指针所指向的对象,立即将指针置为
0,这样就非常清楚地表明指针不再指向任何对象。
|
const 对象的动态分配和回收
C++ 允许动态创建 const 对象:
// allocate and initialize a const object
const int *pci = new const int(1024);
与其他常量一样,动态创建的 const 对象必须在创建时初始化,并且一经初始化,其值就不能再修改。上述
new 表达式返回指向 int 型
const 对象的指针。与其他 const 对象的地址一样,由于 new 返回的地址上存放的是
const 对象,因此该地址只能赋给指向 const 的指针。
对于类类型的 const 动态对象,如果该类提供了默认的构造函数,则此对象可隐式初始化:
// allocate default initialized const empty string
const string *pcs = new const string;
new 表达式没有显式初始化 pcs 所指向的对象,而是隐式地将 pcs
所指向的对象初始化为空的 string 对象。内置类型对象或未提供默认构造函数的类类型对象必须显式初始化。
下面三种常见的程序错误都与动态内存分配相关:
-
删除( delete
)指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory
leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来。
-
读写已删除的对象。如果删除指针所指向的对象之后,将指针置为 0
值,则比较容易检测出这类错误。
-
对同一个内存空间使用两次 delete
表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 delete
运算,将该对象的内存空间返还给自由存储区,然后接着 delete
第二个指针,此时则自由存储区可能会被破坏。
操纵动态分配的内存时,很容易发生上述错误,但这些错误却难以跟踪和修正。
|
删除 const 对象
尽管程序员不能改变 const 对象的值,但可撤销对象本身。如同其他动态对象一样,
const 动态对象也是使用删除指针来释放的:
delete pci; // ok: deletes a const object
即使 delete 表达式的操作数是指向 int 型 const
对象的指针,该语句同样有效地回收 pci 所指向的内容。
分享到:
相关推荐
### C++动态分配内存详解 #### 一、基本概念与基础知识自测题解析 ##### 7.1 填空题解析 **7.1.1 C/C++定义了4个内存区间:** - **代码区**:存放程序代码,包括函数体、字符串常量等不可变的数据。 - **全局...
在C++中,`new`运算符用于在堆上分配内存,而`delete`运算符用于释放内存。当使用`new`创建一个对象时,它返回一个指向新分配内存的指针,这个对象在堆中创建,而不是在栈上。例如,`int *pi=new int(0)`会在堆上...
动态分配内存是编程中一个重要的概念,特别是在操作系统层面。它允许程序在运行时根据需要请求内存,而不是在编译期间预设固定的内存空间。在C++中,动态内存分配是通过一组内置于语言中的函数来实现的,这些函数...
`new`用于动态分配内存,而`delete`用于释放已分配的内存。在C++中,这两个运算符可以被重载以自定义内存管理行为。通过重载它们,我们可以添加额外的逻辑,比如记录分配的内存块、检查是否正确释放等。 1. **重载`...
`会为一个整数分配内存,并返回指向它的指针。对于数组,可以写成`int *arr = new int[5];`来创建包含五个整数的数组。 2. **delete运算符**:与`new`对应的是`delete`运算符,用于释放由`new`分配的内存。当不再...
当使用`new[]`为数组分配内存时,必须使用`delete[]`来释放这些内存。这是因为`new[]`不仅为数组元素分配内存,还会初始化这些元素。而`delete[]`除了释放内存之外,还会为每个数组元素调用析构函数。 ```cpp int * ...
1. **内存管理**:C++代码需要管理和分配内存空间,以创建虚拟硬盘。这涉及到动态内存分配(如`new`运算符)和释放(如`delete`运算符),以及可能的内存池策略,以优化内存的分配和回收。 2. **文件系统接口**:...
1. **首次适配(First Fit)**:这是最基础的内存分配策略,它简单地将空闲块按大小顺序排列,当需要分配内存时,选择第一个足够大的空闲块。 2. **最佳适配(Best Fit)**:与首次适配不同,最佳适配试图找到最小...
例如,可以创建一个全局的分配计数器,每当分配内存时增加,释放内存时减少。如果计数器不为零,就表明存在内存泄漏。 2. **工具辅助检测**:使用专门的内存泄漏检测工具,如Valgrind、LeakSanitizer(asan)等。...
在C++编程语言中,动态内存分配是一种在程序运行时而非编译时为变量或对象分配内存的方法。这种分配方式允许程序根据需要在运行时决定内存的大小和生命周期,这在处理不确定数量的数据或者需要创建复杂的数据结构时...
C++动态分配内存(new)和撤销内存(delete) 在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而...
`new`是C++中的动态内存分配运算符,它用于在堆上为对象分配内存。当调用`new T`时,会返回一个指向新创建的`T`类型对象的指针。对于数组,`new[]`可以用来分配一系列相同类型的对象。例如,`new int[5]`将分配一个...
在C++编程中,动态数组是一种非常重要的概念,它允许我们在程序运行时根据需要分配内存。这与静态数组不同,静态数组在编译时就需要确定大小,并且一旦定义后其大小不可更改。动态数组则可以在运行时根据输入或计算...
动态存储分配是指在程序运行时根据需求分配内存空间,系统根据要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。 在 C++ 中,申请和释放堆中分配的存贮空间,分别使用 new 和 delete ...
首先,`new`操作符用于在堆上动态地分配内存。当程序执行到`new`表达式时,系统会在内存堆中找到一块足够大的连续区域,并返回该区域的起始地址。例如,如果你想要创建一个整型变量,你可以这样做: ```cpp int* ...
掌握C++内存管理是提升编程能力的关键,理解内存分配机制、正确使用`new`和`delete`,以及注意潜在的内存泄漏问题,都是成为C++高手的必经之路。虽然现代的编程语言如Java和.NET提供了自动内存管理,但牺牲了C++的...
2. **堆内存分配**:在C++中,我们使用`new`运算符动态地在堆上分配内存。例如,`int* ptr = new int;` 创建了一个整型变量,并返回指向它的指针。使用`delete`运算符可以释放这块内存,如`delete ptr;`。然而,不...
内存泄漏是C++编程中一个严重的问题,它指的是程序在申请内存后,无法释放已申请的内存空间,一次小的内存泄漏可能看似无害,但随着时间推移,大量的内存泄漏会消耗掉系统的可用内存,导致性能下降甚至系统崩溃。...
首先,传统的数组在C++中的使用需要程序员手动管理内存,包括分配内存、复制数据、调整数组大小以及释放内存等步骤。若直接在函数内部使用new操作符为数组分配内存,一旦数组大小需要调整,就不能简单地使用realloc...
1. 动态内存分配:C++中的`new`操作符用于在堆上分配内存,返回一个指向新分配内存的指针。对应的`delete`操作符用于释放内存。使用动态内存时,程序员必须确保正确地释放所有分配的内存,否则会导致内存泄漏。另外...