新建和删除运算符在库

时间:2015-12-11 13:06:37

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

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

在库中运送内存管理工具通常是错误的,或者在某些情况下仅为某些特定类提供内存管理是好的,只定义特定于类的 new 删除运算符覆盖?

静态链接库的情况是否存在差异?

2 个答案:

答案 0 :(得分:8)

一般来说,这被标记为“这里是龙”。这取决于各种各样的事情。通常这两个图书馆都会争吵,而新的和删除最终会被其中一个图书馆覆盖 - 这是你所能想到的最好的。

备选方案:

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

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

答案 1 :(得分:8)

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

例如,如果你看一下std :: vector,你会注意到它存储的类型以及分配器都是模板化的。通过编写一致的分配器,您可以精确控制std :: vector如何分配和取消分配内存。注意这是多么好和松散耦合:即使你不能改变任何原始的std :: vector源代码,你也可以完全控制内存分配。

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

  1. 以std :: allocator的方式编写符合分配器概念的分配器。
  2. 确保直接使用动态内存分配的所有类(例如,不通过其中一个成员)可以识别分配器。
  3. 键入所有这些类,以便它们默认使用您的分配器。
  4. 为了澄清第3步,我的意思是在你的库的基本头文件中写这样的东西:

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

    现在你可以在你的库中的任何地方使用''vector'',这将是一个普通的向量,但使用你的分配方案。

    步骤1可以从非常容易(对于无状态分配器)到非常棘手(有很多有状态分配器的问题)。至于步骤2,就容器的动态内存而言,它非常简单,因为标准库中的所有容器都已支持此功能。但是,如果您使用动态内存,例如多态性,你需要做一些额外的工作(可能写一个合适的包装器)以分配器识别的方式做到这一点。

    如果某人有很好的理由说明为什么你想要覆盖新的/删除而不是使用分配器(例如因为有些东西你不能用分配器)我会有兴趣听到它们。

    编辑:只是为了得到这个完整的圆圈,请注意,如果你这样做的话,同时使用库A和B将没有任何问题,因为没有覆盖全局运算符。