启用了RTTI的dynamic_cast segfault

马托维奇

我对dynamic_cast如何将数组的元素强制转换为更大的类感到好奇(它会将所有其他元素都移位了吗?)。所以我写了一个小代码尝试一下。但是我很惊讶,因为它在第一行只是编译而出现段错误。为什么 ?

#include <iostream>

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

class B : public A
{
public:
    int x;
};

class C : public A
{
public:
    int x;
    int y;
};

int main()
{
    A* aArray = new B[2];
    (dynamic_cast<B&>(aArray[0])).x = 1; //segfault here
    (dynamic_cast<B&>(aArray[1])).x = 2;

    (dynamic_cast<C&>(aArray[0])).y = 3;

    std::cout << (dynamic_cast<B&>(aArray[1])).x << std::endl;

    return 0;
}
桑坦德

我来啦。我编译并使用gdb运行

首先,我设置打印对象选项:

(gdb) set print object

检查aArray的地址

(gdb) print aArray
$1 = (B *) 0x8003a404

检查A和B的大小

(gdb) print sizeof(B)
$2 = 8
(gdb) print sizeof(A)
$3 = 4

获取aArray的地址[0]

(gdb) print &aArray[0]
$4 = (B *) 0x8003a404

获取aArray的地址[1]

(gdb) print &aArray[1]
$5 = (A *) 0x8003a408

引用链接问题中答案

如果查看表达式p[1]p它是Base*(Base是完全定义的类型),1是int,因此根据ISO / IEC 14882:2003 5.2.1 [expr.sub],此表达式有效且与*((p)+(1))

从5.7 [expr.add] / 5开始,将整数添加到指针时,只有当指针指向数组对象的元素并且指针算术的结果也指向该元素时,才可以很好地定义结果数组对象或数组末尾的一个。但是,p不指向数组对象的元素,而是指向派生对象的基类子对象。是派生对象是数组成员,而不是基础子对象。

在这种特定情况下,指针算法的实现是通过指针类型的大小来增加指针内存(但请参考此答案以获取更多细微差别)。

的作用aArray + 1是指向类型A的对象数组的第二个元素

符合:

(gdb) print (A*)(((char *)aArray) + sizeof(A))
$6 = (A *) 0x8003a408

...但是aArray实际上是B型对象的数组。

因此,数组的第二个元素是:

(gdb) print &((B *)aArray)[1]
$6 = (B *) 0x8003a40c

因此您最终指向第一个B对象的中间某处...而该访问导致了分段错误。

有关替代说明的示例,请参见:[ http://www.parashift.com/c++-faq/array-derived-vs-base.html]

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章