一个C++的内存池和内存管理的实现(九)

本文详细探讨了智能指针的使用场景与注意事项,强调了确保指针指向内存池分配的内存块的重要性,以及如何正确初始化智能指针以避免资源泄露。同时,文章还提供了智能指针在函数调用、参数传递和返回值中的应用指导,并讨论了如何处理第三方库提供的非智能指针返回值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一章说了智能指针的使用。这里还有几个使用上要注意的地方。

首先,必须确保指针指向的是内存池里分配出来的内存块。比如下面这样是不行的。如果这么用的话,指针内容访问的时候,会抛出异常来。因为那个m_nUnmanagedLen得不到正确值(不是内存池里的内存块,没有合法的前缀),造成m_pData->m_pEndMemPtr错误。

int A[100];
HEAP_MEM_PTR<int> p = A;  // 错误

下面这两个也不行,因为给p1,p2赋值的时候等号右方没有指向内存块的起始地址,同样得不到正确的内存块的前缀,从而得不到正确的内存可用范围

int* A = NEW int[100];
HEAP_MEM_PTR<int> p1 = &A[16];  // 错误
HEAP_MEM_PTR<int> p2 = A+16;  // 错误

再看看下面这个。给p2赋值的那个之所以是正确的,是因为我们为SmartHeapMemPtr类重写了operator+函数,里面做了正确的处理。而p1赋值的那个,仍然是把某个没有指向内存块起始位置的指针赋给了p1,导致p1找不到正确的内存块前缀。当然,也许可以重写一下地址符函数来解决这个问题,这个光荣的任务就交给读者自己了。

HEAP_MEM_PTR(int) A = NEW int[100];
HEAP_MEM_PTR<int> p1 = &A[16];  // 错误
HEAP_MEM_PTR<int> p2 = A+16;  // 正确

总结一下,要使用HEAP_MEM_PTR智能指针来检查越界,必须在初始化赋值时要么赋给它另一个HEAP_MEM_PTR对象,要么赋给它普通的指针,但是这个指针必须是指向有特殊前缀的(即通过内存池分配的)内存块的起始地址。所以,归纳为如下的使用原则:
1. 所有指针定义用HEAP_MEM_PTR代替,不要出现int* A这样的语句。
2. 不要用地址符。
3. 以上两条必须贯穿整个程序,包括函数传参和返回

比如下面这个函数

float* Func1(float *p1);

必须改成这样

HEAP_MEM_PTR(float) Func1(HEAP_MEM_PTR(float) p1);

为啥?我如果在其他函数里调用了Func1,像下面那样

void main()
{
    HEAP_MEM_PTR(float) p1;
    ...
    HEAP_MEM_PTR(float) p2 = Func1(p1);
    ...
}

对于main函数来说,如果Func1的返回就是个普通指针,怎么保证它指向的是一块有特殊前缀的内存的首地址?无法保证。一旦Func1做不到这点,以后对p2的使用就有可能抛出异常。所以还是返回智能指针比较保险。同理,对于Func1里面的智能指针的使用来说,也必须保证传进来的参数指向有特殊前缀的内存的首地址。

那么如果Func1是第三方库提供的怎么办?你需要知道返回的指针所指的内存长度,并显式的设定给智能指针,如下:

void main()
{
    HEAP_MEM_PTR(float) p1;
    ...
    HEAP_MEM_PTR(float) p2 = Func1(p1);
#ifdef USE_SMART_HEAP
    p2.SetUnmanagedLength(1024);  // 假设我们知道返回的指针指向的是一个1024字节的数组。
#endif
    ...
}

A同学问了:那如果不知道返回给你的内存的长度怎么办?那还能怎么办,p2就定义成普通指针吧,就别用智能指针来查越界了。

A同学又问了,上面的程序有个问题啊。我如果要释放p2所指的内存,DEL_ARRAY会不会产生问题?当然,因为那内存分配是第三方库管的,不是从我们的内存池分配的。不过释放p2需要我们来操心么?哪分配哪释放不是应该是C++编程尽可能遵循的原则么?

可是,你也说了那是尽可能。好吧,万一需要我们来释放,就只能把p2定义成float*,删除时用delete了。这么ugly的库,你确定要用吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值