关于指针下行转换后,内存越界访问的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010021282/article/details/53872137

今天被一个派生类指针内存越界访问的问题纠缠了半边,还是学艺未精啊,赶紧总结一下…

首先,有这么两个类:

class A
{
public:
    ~A();
};

class B:public A
{
public:
    void SetValue(int val){m_ivalue = val;}
    int  GetValue(){return m_ivalue;}
private:
    int  m_ivalue;
};

指针经过下行转换,然后访问派生类成员(内存越界):

A* pa = new A();
B* pb = static_cast<B*>(pa);
pb->SetValue(1234);
cout<< "The value is :" << pb->GetValue()<<endl;

运行结果却是。。。正常运行!!
这里写图片描述

这就尴尬了。。pb指向的内存是通过new A申请的,怎么还有m_ivalue的事?

仔细琢磨了一下,其实也不是很难理解,只要理清楚内存分布:

A的大小是4byte(只有一个虚函数表),new A申请到的堆内存大小自然也是4byte,而B的大小是8byte,

B的内存分布是这样的:
0-4byte: B的虚函数表
5-8byte:m_ivalue

而上例中pb指向的堆内存分布是这样子的:
0-4byte:A的虚函数表
大于4byte:未分配或者被用于其他”申请者”

当执行pb->SetValue(1234);语句时,其实是往pb偏移4byte的地址写入1234,但是从上面可以看到,这部分内存是没有经过申请的,难道也可以直接使用吗?

其实是可以的。

我将main函数改成如下:

A* pa = new A();
B* pb = static_cast<B*>(pa);
pb->SetValue(1234);
int *pi = (int*)pb;
pi += sizeof(A)/sizeof(int);//偏移4个字节
*pi = 4321;
cout<< "\r\n   The value is :" << pb->GetValue()<<endl;

这里定义一个int类型的指针,直接操作该内存。
运行结果:
这里写图片描述

可以看到,值4321被成功写入,说明没有申请的堆内存,其实是可读可写的。

我也想不明白为什么要这么设定,这样导致的后果就是看起来程序没有任何问题,但是指不定什么时候,就会操作到“别人”申请的内存,调试也麻烦得很。

猜你喜欢

转载自blog.csdn.net/u010021282/article/details/53872137