库中的新运算符和删除运算符替代
New and delete operators override in libraries
如果两个库(动态链接)有自己的全局重写版本的new和delete运算符,并且它们使用自己的内存管理,会发生什么?
在库中提供内存管理设施通常是错误的吗?或者在某些情况下,只为某些特定类提供内存管理,只定义特定于类的new和delete运算符覆盖是否是好的?
静态链接库的情况有什么不同吗?
通常,这被标记为"这里有龙"。这取决于各种各样的事情。通常,这两个库会发生冲突,新建和删除最终会被其中一个库覆盖——这是你所能期望的最好结果。
备选方案:
-
库A启动。覆盖新建/删除,分配一些内存。库B启动并覆盖。在系统关闭时,库A的内存会随着库B的删除而释放。这不好。
-
库A中分配的内存使用库A的覆盖,库B也是如此。如果最终库A中的内存被库B释放,那么您将失败。(这可能更令人困惑,因为如果B删除的对象有一个虚拟析构函数,那么删除可能最终由a完成……所以它是有效的。)
我认为Martin很好地回答了你的问题,他概述了发生了什么,也没有什么是有点危险和不太可取的(确实有龙)。让我通过提供一个替代方案来扩展它:避免覆盖new/delete,而是使用分配器的概念。
例如,如果您查看std::vector,您会注意到它存储的类型和分配器都是模板化的。通过编写一个一致的分配器,您可以精确地控制std::vector如何分配和取消分配内存。请注意这是多么的好和松散耦合:即使不能更改任何原始的std::vector源代码,也可以轻松地对内存分配进行完全控制。
如果你想让图书馆B以特定的方式进行分配,我会做的是:
- 以std::allocater的方式编写一个符合分配器概念的分配器
- 确保所有直接使用动态内存分配的类(例如,不通过其成员之一)都具有分配器意识
- Typedef所有这些类,以便它们在默认情况下使用您的分配器
为了澄清步骤3,我的意思是在库的基本头文件中写这样的东西:
template <class T>
using my_lib::vector = std::vector<T, my_lib::MyAllocator<T>>;
现在,您可以在库中的任何位置使用"vector",这将是一个正常的向量,但使用您的分配方案。
步骤1的范围从非常简单(对于无状态分配器)到非常棘手(有状态分配器有很多问题)。至于步骤2,容器的动态内存非常简单,因为标准库中的所有容器都已经支持这一点。但是,如果您使用动态内存来实现多态性,则需要做一些额外的工作(可能需要编写一个合适的包装器),才能以分配器感知的方式实现这一点。
如果有人有很好的例子说明为什么你想覆盖new/delete而不是使用分配器(例如,因为有一些事情你不能用分配器),我很想听听他们的意见。
编辑:请注意,如果同时使用库A和库B,则不会有任何问题,因为没有覆盖全局运算符。
- 编译"运算符删除"时C++编译器如何工作?
- 删除 x 与 ::运算符删除 (x)
- 未找到匹配的运算符删除;如果初始化引发异常,内存将不会被释放
- 为什么在运算符删除中不调用析构函数?
- 如何在 C++ 中使用删除运算符删除单个数据
- C++对自动(堆栈)指针使用运算符删除
- C++运算符删除覆盖并不总是使用
- 带大小参数和不带大小参数的"运算符删除":当两者都可用时,选择哪一个?
- C++ 运算符删除重载对派生类不起作用
- 无法覆盖C++中纯抽象类中的运算符删除/新建
- 对运算符删除覆盖的工作方式感到困惑
- C++/析构函数-运算符删除
- C++can运算符删除失败,如果不是原因
- 如果我写一个新的展示位置?我应该如何编写普通运算符删除
- 删除与运算符删除(和无效指针)
- 使用单个删除运算符删除多个指针
- 如何实现 C "classes" 的 C++11 冒名顶替者的运算符删除?
- shared_ptr-运算符删除中的访问冲突
- 使用delete运算符删除结构中的元素
- 内存管理 - 目标 C++ 运算符删除