1 new运算符的拓展
1.1 自由存储区与堆的概念
在C++中,内存区分为5个区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区。
自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。
new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。
那么自由存储区是否能等于堆(问题等价于new是否能在堆上动态分配内存),这取决于operator new 的实现细节。自由存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。
1.2 new定位运算符概念和简单使用方法
new定位运算符的概念:
通常,new负责在堆(heap)中找到一个能够满足要求的内存块。new运算符还有一种变体,被称为定位(placement)new运算符,他能让你能够指定要使用的位置。程序员可以使用这种特性来设置其内存管理规程、处理需要通过特定地址进行访问的硬件或在特定位置创建对象。
new定位运算符的使用场景:
- 内存池管理:在内存池中预先分配一大块内存,然后在其中构造对象。
- 自定义内存分配策略:在特定的内存区域(如共享内存、内存映射文件等)中构造对象。
- 性能优化:通过减少内存分配和释放的开销来优化性能。
new定位运算符语法:
ptr = (Type*)new (ptr) TypeName;
其中 ptr 是一个指向已分配内存的指针,TypeName 是要构造的对象类型。
下面给出实例代码,定位new作用于简单类型的使用方法
#include <iostream>
using namespace std;
void assign_value(int *p, int num, int test)
{
for (int i = 0; i < num; i++)
{
p[i] = i + test;
}
}
void print_value(int *p, int num)
{
for (int i = 0; i < num; i++)
{
std::cout << p[i] << " ";
}
std::cout << std::endl;
}
int main()
{
char buffer[40]; //缓冲区
cout << "buffer[40] address=" << (void*)buffer << endl;
int* p1 = new int[10]; //常规new运算符
std::cout << "p1 address" << p1 << std::endl;
assign_value(p1, 10, 0);
print_value(p1, 10);
int* p2;
p2 = new(buffer) int[10]; //定位new运算符
cout << "p2 address=" << p2 << endl;
assign_value(p2, 10, 50);
print_value(p2, 10);
int* p3;
p3 = new(buffer) int[10]; //定位new运算符
cout << "p3 address=" << p3 << endl;
assign_value(p3, 10, 100);
print_value(p3, 10);
print_value(p2, 10);
int* p4;
p4 = new(buffer + 2 * sizeof(int))int;
cout << "p4 address=" << p4 << endl;//偏移2个int字节的新地址
print_value(p4, 8);
delete p1;
delete p2;
delete p3;
delete p4;
return 0;
}
执行结果如下:
1.3 定位new作用于复杂数据类型