C++技术细节:多维数组、内存节省与管理
立即解锁
发布时间: 2025-08-16 01:07:42 阅读量: 22 订阅数: 97 


C++编程语言精要与实践指南
# C++ 技术细节:多维数组、内存节省与管理
## 1. 多维数组使用注意事项
在处理多维数组时,要注意代码的规范性。例如,最后一次调用使用 `&v v[0 0][0 0]` ,其实 `v v[0 0]` 也可以,因为它们是等价的,但使用 `v v` 会导致类型错误。这种微妙且杂乱的代码最好进行封装隐藏。若必须直接处理多维数组,可考虑将依赖它的代码封装起来,这样能减轻后续程序员处理代码的负担。提供一个带有合适下标运算符的多维数组类型,可让大多数用户无需担心数组中数据的布局。而标准的 `vector` 则不存在这些问题。
## 2. 节省内存空间的方法
在编写非平凡应用程序时,常常会面临内存空间不足或成本过高的问题。可以通过以下两种方式从现有内存中挤出更多空间:
- **将多个小对象放入一个字节**:可通过使用字段来实现。
- **在不同时间使用相同空间存储不同对象**:可通过使用联合来实现。
不过,许多字段和联合的使用属于纯优化操作,且这些优化往往基于对内存布局的非可移植假设。因此,程序员在使用它们之前应三思而后行。通常,更好的方法是改变数据的管理方式,例如更多地依赖动态分配的存储,减少对预分配(静态)存储的依赖。
### 2.1 字段的使用
在 C++ 中,使用整个字节(如 `char` 或 `bool`)来表示一个二进制变量(如开关)似乎有些浪费,因为 `char` 是 C++ 中可独立分配和寻址的最小对象。但可以将多个这样的小变量作为字段捆绑在一个 `struct` 中。通过指定成员占用的位数来定义字段,也允许使用未命名的字段,它们不影响命名字段的含义,但可用于以某种依赖于机器的方式优化布局。
以下是一个示例:
```cpp
struct P PN {
// R6000 Physical Page Number
unsigned int P FN : 22; // Page Frame Number
int : 3; // unused
unsigned int C CA : 3; // Cache Coherency Algorithm
bool nonreachable : 1;
bool dirty : 1;
bool valid : 1;
bool global : 1;
};
```
这个例子还展示了字段的另一个主要用途:为外部强加的布局部分命名。字段必须是整数或枚举类型,且不能获取字段的地址,但除此之外,它的使用方式与其他变量完全相同。需要注意的是,`bool` 字段确实可以用单个位来表示。
在操作系统内核或调试器中,`P PN` 类型可能会这样使用:
```cpp
void part_of_VM_system(P PN* p)
{
// ...
if (p->dirty) { // contents changed
// copy to disc
p->dirty = 0;
}
// ...
}
```
令人惊讶的是,使用字段将多个变量打包到一个字节中并不一定能节省空间。虽然它节省了数据空间,但在大多数机器上,操作这些变量所需的代码大小会增加。有案例表明,将二进制变量从位字段转换为字符后,程序的大小会显著缩小。此外,访问 `char` 或 `int` 通常比访问字段要快得多。字段只是使用按位逻辑运算符从字的一部分提取信息和插入信息的便捷简写。
### 2.2 联合的使用
联合是一种特殊的 `struct`,其中所有成员都分配在相同的地址,因此联合只占用其最大成员所需的空间。自然地,联合一次只能为一个成员保存值。
例如,考虑一个符号表条目,它包含一个名称和一个值:
```cpp
enum Type { S, I };
struct Entry {
char* name;
Type t;
char* s; // use s if t==S
int i; // use i if t==I
};
void f(Entry* p)
{
if (p->t == S) cout << p->s;
// ...
}
```
在这个例子中,`s` 和 `i` 永远不会同时使用,因此会浪费空间。可以通过将它们指定为联合的成员来轻松回收空间:
```cpp
union Value {
char* s;
int i;
};
struct Entry {
char* name;
Type t;
Value v; // use v.s if t==S; use v.i if t==I
};
void f(Entry* p)
{
if (p->t == S) cout << p->v.s;
// ...
}
```
但引入联合后,需要将代码中的 `s` 改为 `v.s`。为了避免这种情况,可以使用匿名联合,它没有名称,因此不会定义类型,只是确保其成员分配在相同的地址:
```cpp
struct Entry {
char* name;
Type t;
union {
char* s; // use s if t==S
int i; // use i if t==I
};
};
void f(Entry* p)
{
if (p->t == S) cout << p->s;
// ...
}
```
这样,使用 `Entry` 的所有代码都无需更改。
使用联合时,如果总是通过写入成员的方式来读取其值,这属于纯优化操作。但要确保联合仅以这种方式使用并不容易,误用可能会引入微妙的错误。为避免错误,可以封装联合,以保证类型字段与访问联合成员之间的对应关系。
联合有时会被误用于
0
0
复制全文
相关推荐










