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

一、内存池的缺陷

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

二、指针类型转换

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

#include 
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 
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

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

三、嵌入式指针

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

你可能感兴趣的:(c++,开发语言)