代码之家  ›  专栏  ›  技术社区  ›  BuschnicK

库强制全局重载new/delete!

  •  5
  • BuschnicK  · 技术社区  · 16 年前

    我正在维护一个大型闭源应用程序的插件(实现为一个DLL)。多年来,这种方法一直很有效。然而,随着对其SDK的最新更新,供应商重载了全局运算符new和delete。这给我带来了很多麻烦。结果是我的插件分配了一个字符串。我将这个字符串传递到一个静态链接的库中,该库会修改它(更改它的长度,从而重新分配它)。我的应用程序崩溃。

    当然,原因是字符串位于供应商分配的自定义堆上。静态链接库不知道这个堆,并尝试在该内存上使用默认的new/delete操作符。繁荣。

    现在的问题是:如何保持代码的整洁并避免使用供应商的操作员?没有条件预处理器宏。我不能避免包含有问题的头,因为它包含了我需要的2000行插件代码。我不能将提供的分配器传递到另一个库中,因为它没有为此提供任何机制。我已经向卖主投诉过了。我不知道还能尝试什么?

    附录: 经过激烈的争论,我设法说服供应商再次从下一个版本的SDK中消除过载。我已经通过简单地破解当前的SDK并手动移除过载来解决了我的直接问题。谢谢你在这篇文章中的所有建议。它们起到了争论和进一步的“证明”的作用,证明了为什么超载在一开始是一个坏主意。

    4 回复  |  直到 16 年前
        1
  •  4
  •   Terry Mahaffey    16 年前

    如果您正在(通过包含头)编译一个重写的new/delete运算符,那么您的代码中所有调用new/delete都将使用它们。无法重新覆盖它(链接错误),或者只能部分覆盖它,等等。

    重写全局新建/删除运算符是一种糟糕的形式。这是个坏主意。如果你不知道为什么这是个坏主意,你就没有资格这么做。如果你真的意识到这是个坏主意的原因,你就有资格这么做,但你通常会选择不这样做。

    定义全局新建/删除在您希望人们直接包含到其项目中的组件中更糟糕。作为客户,您的工作是帮助供应商了解情况的严重性,或者停止成为他们的客户。

    可以定义自定义分配器类型(请参见 link for a good tutorial 关于如何这样做,需要接口等),并将其专门用于STL类型(这是一个模板参数)。

    对于共享的指针,您需要做一些不同的事情:如果您不希望使用默认的“delete p”行为,它将一个deleter对象作为构造函数的参数。这不是自定义分配器;它只是一个常规的一元函数。

        2
  •  2
  •   James    16 年前

    这样做不可能:

    namespace evil{
    
    #include "evil_header.h"
    
    }
    

    那么,邪恶头声明为全局新建/删除的内容将变为邪恶::新建/邪恶::删除。但我怀疑,如果在邪恶的头中声明的东西有非头的定义,这将起到很好的作用。

        3
  •  1
  •   Joan Rieu    16 年前

    您可以在命名空间中使用另一个新的:

    namespace MyNS {
        // Declare your new/delete operators here
        // and also declare a class implementing the same interface as std::allocator
        // using your newly created memory management functions.
        // Don't forget to put all your classes in the namespace.
        // (if you don't have one already)
    }
    

    然后可以使用所有STL类,将分配器类型作为模板参数。

        4
  •  0
  •   doron    16 年前

    一种选择是创建自己的重载新运算符,该运算符可以用malloc实现。

    这可以定义为:

    enum MyNew {EMyNew};
    
    void *operator new(size_t size, MyNew);
    

    你可以这样称呼它 MyClass* myClass = new (EMyNew)MyClass;

    因为这是用malloc实现的,所以它应该按预期工作。唯一令人沮丧的是,你将不得不替换所有你使用过的新实例。