【问题标题】:New and delete operators override in libraries库中的新建和删除运算符覆盖
【发布时间】:2015-12-11 13:06:36
【问题描述】:

如果两个库(动态链接)有自己的全局覆盖版本的 newdelete 运算符,并且它们使用自己的内存管理,会发生什么情况?

在库中提供内存管理设施通常是错误的,还是在某些情况下只为某些特定类提供内存管理,只定义类特定的 new删除运算符覆盖?

静态链接库的情况有什么不同吗?

【问题讨论】:

  • 您有特定的用例? newdelete 可以被覆盖,但是有什么用呢?或者这是一个理论问题(我认为这将是针对非常高级的用户和用途)?
  • 就标准 C++ 而言,动态链接库不存在,因此您的问题是特定于平台的。您对特定平台感兴趣吗?
  • @SebastianRedl unix 相关,.so
  • @Elyasin 用例:内存池实现

标签: c++ new-operator delete-operator


【解决方案1】:

通常,这被标记为“这里有龙”。这取决于各种各样的事情。通常这两个库会发生冲突,而 new 和 delete 最终会被其中一个覆盖 - 这是您所希望的最好的结果。

替代方案:

  • 库 A 启动。覆盖 new/delete,分配一些内存。库 B 启动并覆盖。在系统关闭时,库 A 的内存随着库 B 的删除而被释放。这不好。

  • 在库 A 中分配的内存使用库 A 的覆盖,对于库 B 也是如此。如果您最终在库 A 中分配的内存被库 B 释放,您将丢失。 (而且它可能更令人困惑,因为如果 B 删除的对象具有虚拟析构函数,则删除最终可能由 A 完成......所以它可以工作。)

【讨论】:

    【解决方案2】:

    我认为马丁很好地回答了你的问题,概述了发生的事情,也没有什么有点危险并且不是非常可取的(确实有龙)。让我通过提供一个替代方案来扩展它:避免覆盖 new/delete,而是使用分配器概念。

    例如,如果您查看 std::vector,您会注意到它既针对其存储的类型进行了模板化,也针对分配器进行了模板化。通过编写符合要求的分配器,您可以准确控制 std::vector 如何分配和取消分配内存。请注意这是多么好的和松耦合:即使您无法更改任何原始 std::vector 源代码,您也可以毫无困难地完全控制内存分配。

    如果您希望库 B 以特定方式进行分配,我会做的是:

    1. 按照 std::allocator 的方式编写符合分配器概念的分配器。
    2. 确保所有直接使用动态内存分配(例如,不通过其成员之一)的类都可以识别分配器。
    3. Typedef 所有这些类,以便它们默认使用您的分配器。

    为了阐明第 3 步,我的意思是在你的库的基本头文件中编写类似这样的内容:

    template <class T>
    using my_lib::vector = std::vector<T, my_lib::MyAllocator<T>>;
    

    现在您可以在库中的任何位置使用“向量”,这将是一个普通向量,但使用您的分配方案。

    第 1 步的范围可以从非常简单(对于无状态分配器)到相当棘手(有许多与有状态分配器有关的陷阱)。至于第 2 步,就容器的动态内存而言,这非常简单,因为标准库中的所有容器都已经支持这一点。但是,如果您正在使用动态内存,例如多态性,你需要做一些额外的工作(可能编写一个合适的包装器)以一种分配器感知的方式来做到这一点。

    如果有人有很好的例子说明您为什么要覆盖 new/delete 而不是使用分配器(例如,因为有些事情您不能使用分配器),我很想听听他们的意见。

    编辑:只是为了完整循环,请注意,如果您这样做,同时使用库 A 和 B 不会有任何问题,因为没有覆盖全局运算符。

    【讨论】:

    • 我原以为“这里有龙”的意思很清楚,意思是“不要那样做”,但 +1 表示提出了一个好的替代方案。
    • @MartinBonner 你说得对,我略微误读了问题/答案。让我稍微改变一下措辞,并不是要简短地卖掉你很好的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 2020-01-09
    • 1970-01-01
    相关资源
    最近更新 更多