当使用非虚拟析构函数“删除”基类时,Clang 和 GCC 会做什么?

2023-11-30

已经有一个问题询问“现实世界”的行为delete指向缺少虚拟析构函数的基类的指针,但问题仅限于非常有限的情况(派生类没有具有非平凡析构函数的成员),并且接受的答案只是说没有办法知道不检查每个编译器的行为。

....但这实际上并不是很有帮助;知道每个编译器might行为不同并不能告诉我们任何有关任何人行为的信息特别的编译器。那么,在这种情况下 Clang 和 G++ 会做什么呢?我假设他们会简单地调用基类析构函数,然后释放内存(对于整个派生类)。是这样吗?

或者,如果无法确定 GCC 和 Clang 的所有版本,那么 GCC 4.9 和 5.1,以及 Clang 3.5 到 3.7 又如何呢?


首先,标准免责声明:这是未定义的行为,因此即使使用一个特定的编译器,更改编译器标志、星期几或您查看计算机的方式也可能会改变行为。

以下所有内容都假设您的析构函数中发生了某种至少稍微不平凡的破坏(例如,对象删除了一些内存,或者包含其他对象本身删除了一些内存)。

在简单的情况下(单继承),您通常会得到大致相当于静态绑定的东西 - 也就是说,如果您通过指向基对象的指针销毁派生对象,则仅调用基构造函数,因此该对象不会正确销毁。

如果您使用多重继承,并通过“第一个”基类销毁派生类的对象,则通常与使用单继承大致相同 - 将调用基类析构函数,但派生类析构函数不会。

如果您具有多重继承并通过指向第二个(或后续)基类的指针销毁派生对象,则您的程序通常会崩溃。通过多重继承,您可以在派生对象中的多个偏移处拥有多个基类对象。

enter image description here

在典型情况下,第一个基类将位于派生对象的开头,因此使用派生对象的地址作为指向第一个基类对象的指针,其工作方式与单继承情况大致相同 - 我们得到等价的静态绑定/静态调度。

如果我们对任何其他基类尝试此操作,则指向派生类的指针不会指向该基类的对象。需要将指针调整为指向第二个(或后续)基类,然后才能将其用作指向该类型对象的指针。

对于非虚拟析构函数,通常会发生的情况是代码基本上会采用第一个基类对象的地址,大致相当于reinterpret_cast并尝试使用该内存,就好像它是指针指定的基类的对象(例如,base2)。例如,假设 base2 在偏移量 14 处有一个指针,并且 base2 的析构函数尝试删除它指向的内存块。对于非虚拟析构函数,它可能会收到一个指向 base1 主题的指针——但它仍然会从那里查看偏移量 14,并尝试将其视为指针,并将其传递给delete。可能是 base1 包含一个位于该偏移量的指针,并且它实际上指向一些动态分配的内存,在这种情况下,这实际上可能看起来成功。话又说回来,也可能是完全不同的东西,并且程序终止并显示一条有关(例如)尝试释放无效指针的错误消息。

也有可能 base1 是smaller大小为 14 个字节,因此最终实际上操作了(例如)base2 中的偏移量 4。

底线:对于这样的情况,事情很快就会变得非常糟糕。您所能期望的最好结果就是程序快速而响亮地终止。

只是为了好玩,快速演示代码:

#include <iostream>
#include <string>
#include <vector>

class base{ 
    char *data;
    std::string s;
    std::vector<int> v;
public:
    base() { data = new char;  v.push_back(1); s.push_back('a'); }
    ~base() { std::cout << "~base\n"; delete data; }
};

class base2 {
    char *data2;
public:
    base2() : data2(new char) {}
    ~base2() { std::cout << "~base2\n"; delete data2; }
};

class derived : public base, public base2 { 
    char *more_data;

public:
    derived() : more_data(new char) {}
    ~derived() { std::cout << "~derived\n"; delete more_data; }
};

int main() {
    base2 *b = new derived;
    delete b;
}

g++/Linux:分段错误
clang/Linux:分段错误
VC++/Windows:弹出窗口:“foo.exe 已停止工作”“出现问题导致程序停止正常工作。请关闭程序。”

如果我们将指针更改为base代替base2,我们得到~base来自所有编译器(如果我们仅从一个基类派生,并使用指向该基类的指针,我们会得到相同的结果:仅运行该基类的析构函数)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当使用非虚拟析构函数“删除”基类时,Clang 和 GCC 会做什么? 的相关文章

  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 如何在 .NET Framework 2.0 中模拟“Func<(Of <(TResult>)>) 委托”?

    我尝试使用这个类代码项目文章 http www codeproject com KB threads AsyncVar aspx在 VB NET 和 NET Framework 2 0 中 除了这一行之外 所有内容似乎都可以编译Privat
  • Directory.Delete 之后 Directory.Exists 有时返回 true ?

    我有非常奇怪的行为 我有 Directory Delete tempFolder true if Directory Exists tempFolder 有时 Directory Exists 返回 true 为什么 可能是资源管理器打开了
  • 如何将非静态类成员“std::bind”绑定到 Win32 回调函数“WNDPROC”?

    我正在尝试将非静态类成员绑定到标准WNDPROC http msdn microsoft com en us library ms633573 aspx功能 我知道我可以通过将类成员设为静态来简单地做到这一点 但是 作为一名 C 11 ST
  • 复制 std::function 的成本有多高?

    While std function是可移动的 但在某些情况下不可能或不方便 复制它会受到重大处罚吗 它是否可能取决于捕获变量的大小 如果它是使用 lambda 表达式创建的 它依赖于实现吗 std function通常被实现为值语义 小缓
  • C中的malloc内存分配方案

    我在 C 中尝试使用 malloc 发现 malloc 在分配了一些内存后浪费了一些空间 下面是我用来测试 malloc 的一段代码 include
  • 在 LINQ 中按 Id 连接多表和分组

    我想按categoryId显示列表产品的名称组 这是我的代码 我想要我的视图显示结果 Desktop PC HP Red PC Dell Yellow PC Asus Red SmartPhone Lumia 720 Blue 我的组模型
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • glibc 堆一致性检查

    根据2008年的帖子 我现在找不到 glibc 堆检查 http www gnu org s libc manual html node Heap Consistency Checking html在多线程环境中不起作用 现在还是2010年
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 如何禁用 fread() 中的缓冲?

    我正在使用 fread 和 fwrite 读取和写入套接字 我相信这些函数用于缓冲输入和输出 有什么方法可以在仍然使用这些功能的同时禁用缓冲吗 Edit 我正在构建一个远程桌面应用程序 远程客户端似乎 落后于服务器 我不知道可能是什么原因
  • 等待进程释放文件

    我如何等待文件空闲以便ss Save 可以用新的覆盖它吗 如果我紧密地运行两次 左右 我会得到一个generic GDI error
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • “接口”类似于 boost::bind 的语义

    我希望能够将 Java 的接口语义与 C 结合起来 起初 我用过boost signal为给定事件回调显式注册的成员函数 这非常有效 但后来我发现一些函数回调池是相关的 因此将它们抽象出来并立即注册所有实例的相关回调是有意义的 但我了解到的
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 使用 %d 打印 unsigned long long

    为什么我打印以下内容时得到 1 unsigned long long int largestIntegerInC 18446744073709551615LL printf largestIntegerInC d n largestInte
  • WebSocket安全连接自签名证书

    目标是一个与用户电脑上安装的 C 应用程序交换信息的 Web 应用程序 客户端应用程序是 websocket 服务器 浏览器是 websocket 客户端 最后 用户浏览器中的 websocket 客户端通过 Angular 持久创建 并且
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData

随机推荐

  • 纯 CSS 卡片的重叠效果

    我正在制作与此示例类似的卡片列表 https codepen io pkunzel pen xxgjrVg window addEventListener load function let cards document querySele
  • 膨胀类 android.support.v7.app.AlertController.RecycleListView 时出错

    我的应用程序无法启动 安装后立即崩溃 我无法理解该错误 我为附加在主活动 xml 文件中的两个片段创建了两个 recyclerView Error E AndroidRuntime FATAL EXCEPTION main Process
  • 在循环内将引号粘贴到字符串中

    使用 R 我想生成多个字符串 例如 modelCheck var1 d bug modelCheck var2 d bug modelCheck var10 d bug 我通常会使用 for 循环并粘贴 如果我不必担心双引号 如下所示 fo
  • 为什么 Collections.Counter 没有对称差异?

    因此 对于集合 您可以执行对称差 这相当于并减交集 为什么 是 Counter 对象不受支持的操作数 而并集和交集仍然有效 扩展我的评论 结果发现它当时被讨论过 但被拒绝了 单击完整消息 及其主题 的链接 我将引用 Raymond Hett
  • 如何移动正交图中的点?

    我正在尝试在迈克 博斯托克创建的以下地图上的某些地理位置添加红点 https bl ocks org mbostock 3795040 我的点会显示 但不会随地图移动 如何编辑代码以使点随地图移动 谢谢 add circles to svg
  • 如何使用javascript从mysql数据库获取数据?

    如果可能的话 如何使用 javascript 从 mysql 数据库获取 并发布 数据 我知道我可以使用 php 和其他语言 但我只需要知道这是否可以用 javascript 实现 提前致谢 这对于 Javascript 来说是不可能的 我
  • 如何响应 UNUserNotification 上的点击?

    我正在使用新的UNUserNotificationiOS 10 中的框架 我可以看到如何添加操作按钮 但是当用户点击通知本身时我如何响应 就我而言 它将是带有一些文本的图像 默认行为是应用程序打开 我可以使用自定义代码来检测我的应用程序是否
  • 如何在pyodbc中使用executemany运行多个SELECT查询

    我使用 PYODBC 根据 pandas 数据帧列的值多次查询 SQL DB 如下所示为值列表 因为我使用 ToList 函数将该列转换为列表 the connection string cnxn pyodbc connect driver
  • 扫描随机数量的浮点数,直到 C 中出现新行

    我正在尝试从包含以下文本的文件中读取 502 601 596 465 464597 599 600 598602 591 596 601588 565 548 260 62 61 595583 595 61 558 561237 241 4
  • 分析 C# 中的方法以了解其运行时间

    我需要获取计时报告以了解在类中运行 C 方法需要多长时间 我考虑使用profiler要做到这一点 输入是类中方法的名称 输出是 什么方法 类调用这个方法 运行该方法的时间量 有哪些工具 商业产品可用于 Visual Studio 2010
  • 在 TypoScript 中获取 FlexForm 配置

    我需要从 pi flexform 获取 typescript 中的 page headerData 如何实现我的要求 page PAGE page headerData 10 TEXT 10 value 我不太确定你真正需要什么 我是gue
  • SlidingDrawer 动画速度

    我是 Android 编程和堆栈溢出的新手 我需要减慢应用程序中 SlidingDrawer 的动画速度 我已经像这样子类化了 SlidingDrawer import android content Context import andr
  • 最大化两个数组元素的乘积之和的算法

    竞赛中有一个问题需要计算仅包含数学和生物科目的班级的表现 所以 没有 数学学生 n 没有 的生物学生 每个学生都有一个单独的分数 数学学生和生物学生的分数分别存储在数组 mathScore 和 bioScore 中 全班成绩计算如下 mat
  • 从存储过程填充 DataGridView

    我使用 SQL Server 2008 创建了一个名为 MyStoreProc 的存储过程 它在管理工具中运行良好 在 VB Net 2008 中 我创建了一个新的数据集和一个新的 TableAdaptor 在此表适配器中 我创建了一个名为
  • 如何从树状数组创建 ul - li 菜单?

    我有一个数组title and children index title始终不为空 children是一个数组 空或非空 Any children have title and children等等 myArray 0 gt title g
  • JTable右键复制/粘贴菜单一键复制单元格数据

    我创建了我的JPopupMenu 它出现在我的JTable当我右键单击一个单元格时 但是 我无法复制单元格中的数据 除非我首先双击然后突出显示数据 然后右键单击当前单元格以外的任何位置以显示弹出菜单和复制选项 我想复制单元格中的数据 而不必
  • Perl - 子例程“Hash::Merge::merge”的深度递归

    下列的this问题 我在那里使用了答案 也发布在这里 现在我失败了 我知道失败可能来自于 return bless self gt merge left right class left 但我不明白可能是什么问题 My code usr b
  • 使用 Windows 服务和 SQL Server 在 OneWay WCF 消息中排队

    我需要为 WCF 服务请求实现一个排队机制 该服务将由客户端以单向方式调用 这些请求消息应存储在 SQL Server 数据库中 并且 Windows 服务对消息进行排队 处理请求的时间是可配置的 如果处理消息时发生错误 则需要重试最多10
  • MySQL 5.7 错误(1093:您无法在 FROM 子句中指定目标表 ___ 进行更新) - 通常的解决方案不起作用

    我有一个表 员工 我试图将一些属性 例如薪水 设置为与表中其他值相同的值 我对这个错误的理解是 可以通过以下解决方法来避免它 使用临时表 UPDATE employees SET salary SELECT salary FROM SELE
  • 当使用非虚拟析构函数“删除”基类时,Clang 和 GCC 会做什么?

    已经有一个问题询问 现实世界 的行为delete指向缺少虚拟析构函数的基类的指针 但问题仅限于非常有限的情况 派生类没有具有非平凡析构函数的成员 并且接受的答案只是说没有办法知道不检查每个编译器的行为 但这实际上并不是很有帮助 知道每个编译