C++内存管理:其五、指针类型转换与嵌入式指针

一、内存池的缺陷

作者在上一版本里面介绍了链表实现内存池,其中有一个小缺陷:虽然较少了cookie的内存损耗,但是加入了一个额外的指针,仍然需要占用内存。我们仔细看内存池的设计思想,可以发现一个关键点:
对于一个内存切片,如果放置在freeList中,才会使用指针。如果被用于构造对象,则这个指针毫无用处。
于是可以想到,可以将一块内存区域,即作为指针使用,又用于构造对象。
方案一:共同体,这个东西过于古早了,不过多解释。
方案二:嵌入式指针。

二、指针类型转换

想要把嵌入式指针讲清楚,先要把指针类型转换讲清楚。
在C++里面,64位操作系统下,所有指针都是八字节,表示一个地址。那么为什么指定指针的类型呢?编译器根据指针定位到这个内存地址之后,根据指针类型去解析这个数据。举个例子,假如是一个int类型的指针,定位到这个地址之后,扫描后面的四个字节,去解析这32位二进制代表的int数字是多少。
说一个看起来违背常识的事情,指针之间转换,基本是不被编译器报错的!!但是有可能解析出来一大堆稀奇古怪的东西,所以最好不要这样做。也就是说,给编译器一个地址和数据类型,编译器就可以解析,至于解析出来的是什么东西,由程序员负责
看代码:

#include <iostream>
using namespace std;

class Test
{
public:
    int m_i;
    int m_j;
};

class A{
public:
    int a;
};

int main()
{
    Test t ;
    t.m_i=1000;
    t.m_j=2;
    A *a=(A*)&t;
    cout<<a->a<<endl;
    cout<<t.m_j;
}

输出结果:

1000
2

说明一点:
(1)Test类的字节数大于A类,将Test指针强转为A类型指针后,相当于使用前面的地址,后面的地址也不会被抛弃,只是当前不用。
(2)不考虑cookie的情况下,a->a相当于解析t的前四位字节,恰好前四位也是int类型,就可以解析出来t.m_i对应的值。

这是大结构体的指针转换为指向小结构体的指针,如果反之会怎么样?
看代码:

#include <iostream>
using namespace std;

class Test
{
public:
    int m_i;
    int m_j;
};

class A{
public:
    int a;
};

int main()
{
    A a;
    a.a =666;
    Test * t = (Test *)&a;
    cout<<t->m_i<<endl;
    cout<<t->m_j;
}

运行结果:

666
-2120222908

第一个成员变量可以正常输出,但是对于第二个成员变量拿到了垃圾数值。但是编译器没有限制这个行为,编译正常,也可以正常退出。

三、嵌入式指针

嵌入式指针的核心思想:在这个结构体不用于存储数据的时候,将前八个字节强转为指针,将多个结构体按照链表进行管理。看代码:

#include <iostream>
using namespace std;

class Test
{
public:
    int m_i;
    int m_j;
    struct Obj  // 相当于在类中定义了一个结构体
    {
        struct Obj* pNext;   // 这个pNext是一个嵌入式指针,64位系统下占了八个字节
    };
};

int main()
{
    Test test1;
    cout << "Test size is "<<sizeof(test1) << endl;
    Test::Obj* pTemp;
    pTemp = (Test::Obj*)&test1;   //类型强转,pTemp实际上指向test1的前两八个字节

    Test test2;
    pTemp->pNext = (Test::Obj*)&test2;  //操作以此类推

    Test test3;
    ((Test::Obj*)&test2)->pNext = (Test::Obj*)&test3;

    ((Test::Obj*)&test3)->pNext = nullptr;

}

注意要点:
(1)struct Obj 定义在Test类里面,但是只是定义,没有创建对象,不会占用空间,所以Test对象的大小是八个字节。

(2)嵌入式指针的一个重要原则:使用嵌入式指针的类的size必须大于指针大小,不然强转会有问题。

(3)示例代码来自侯捷老师的课程,实际上struct Obj 大可不必定义在Test类里面,定义在外面也是可行的。但是考虑到这个struct Obj 只被Test使用,定义在Test中比较规格。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值