C++中指针本身不压缩内存,int*仍占8字节;真正的内存优化靠指针实现的共享、延迟分配、联合体重用、稀疏结构和类型擦除等策略。

指针本身不压缩数据,但能绕过拷贝开销实现逻辑压缩
直接说结论:C++ 中用指针无法减少内存占用本身,int* 还是 8 字节(64 位),和 int 的 4 字节无关。所谓“高度压缩”,实际是指避免冗余副本、延迟分配、共享只读数据——这些靠指针的间接访问能力来组织,而不是靠它变小。
典型场景是大对象池、稀疏结构、或只读视图封装。比如你有一组 1MB 的图像数据,不想为每个 ImageProcessor 实例都复制一份,那就让它们持有一个 const uint8_t* 指向同一块内存。
- 别指望
std::shared_ptr<t></t>能省空间——它内部至少含两个指针(数据 + 控制块),比裸指针还重 - 裸指针(
T*)最轻量,但要求你严格管理生命周期;否则一解引用就segmentation fault -
std::span<t></t>(C++20)本质是轻量视图,底层就是T*+size_t,适合替代原始指针做安全切片
用指针+联合体(union)手动复用内存字段
这是真正能降低内存占用的做法:用 union 让多个字段共用同一段内存,再用指针控制解释方式。适用于协议解析、序列化缓冲区等场景。
例如一个 16 字节 header,前 2 字节是类型码,后 14 字节可能是 IPv4 地址、端口号或标志位,具体看类型码:
立即学习“C++免费学习笔记(深入)”;
struct PacketHeader {
uint16_t type;
union {
uint32_t ipv4_addr;
uint16_t port;
uint8_t flags[14];
};
// 注意:这里不存完整数据,只存指针指向的 buffer 中某偏移
};
<p>// 使用时:
uint8_t<em> buf = get_buffer();
PacketHeader</em> hdr = reinterpret_cast<PacketHeader*>(buf);
// 然后根据 hdr->type 决定怎么解释后续字节
- 必须确保对
union成员的访问符合当前活跃成员(C++17 起有明确规则,但编译器不强制检查) -
reinterpret_cast易出错,建议配合static_assert(offsetof(PacketHeader, ipv4_addr) == 2)验证布局 - 跨平台时注意字节序和对齐:
#pragma pack(1)或alignas(1)很可能必需
指针数组替代二维数组,节省未使用行/列的空间
稀疏矩阵、树形结构、动态分块缓存——这些结构天然不适合连续二维数组。用 T** 或 std::vector<std::unique_ptr<T[]>> 可以只为实际需要的行分配内存。
对比:int grid[1000][1000] 固定占 4MB;而指针数组方式下,若只有 50 行非空,每行平均 200 元素,总内存约 1000 * 8 + 50 * 200 * 4 = 8KB + 40KB ≈ 48KB,差两个数量级。
- 不要写
new int*[N]; for(...) data[i] = new int[M];—— 异常安全差,推荐std::vector<std::unique_ptr<int[]>> - 访问
data[i][j]时多一次指针跳转,CPU 缓存局部性变差,密集计算场景反而更慢 - 如果稀疏度不高(>30% 行非空),考虑压缩格式如 CSR(Compressed Sparse Row),它用三个一维数组 + 指针索引,比指针数组更省内存且利于遍历
用 void* + 类型擦除隐藏大对象,推迟构造与拷贝
某些接口要接收任意类型但又不能模板化(比如 C ABI 兼容、插件系统),可用 void* 暂存地址,配合函数指针完成延迟操作。这不压缩体积,但把构造/析构成本从“必发生”变成“按需发生”。
例如一个事件回调系统:
struct Event {
void* payload; // 不立即 new 大对象
void (*dtor)(void*); // 若 payload 需析构,才设此函数
int type;
};
<p>// 发布时:
Event e{.payload = nullptr, .dtor = nullptr, .type = EVENT_LOG};
if (need_log_payload()) {
auto<em> log = new LogPayload{...};
e.payload = log;
e.dtor = [](void</em> p) { delete static_cast<LogPayload*>(p); };
}
-
void*是类型不安全的,务必配对记录类型信息(如type字段或 RTTI) - 千万别把栈变量地址赋给
payload——函数返回后指针就悬空 - C++17 的
std::any或std::variant更安全,但它们内部仍可能堆分配,体积未必更小
真正压缩内存的关键从来不是指针本身,而是用指针获得的控制权:决定何时分配、是否共享、怎样解释字节。一旦开始手动管理 new/delete 和 reinterpret_cast,对齐、别名规则、生命周期这些细节就不再是理论问题——它们会立刻在 valgrind 报告或随机 crash 里出现。


















