图书馆强迫我全局超载 new/delete !
我正在为一个大型闭源应用程序维护一个插件(作为 dll 实现)。这多年来一直运作良好。然而,随着其 SDK 的最新更新,供应商使全局运算符 new 和 delete 过载。这给我带来很多麻烦。发生的情况是我的插件分配了一个字符串。我将此字符串传递到静态链接库中,该库对其进行修改(更改其长度,从而重新分配它)。我的应用程序崩溃了。
原因当然是,该字符串位于供应商分配的自定义堆上。静态链接库对此堆一无所知,并尝试在该内存上使用默认的 new/delete 运算符。繁荣。
现在的问题是:如何保持代码干净并避免使用供应商的运算符?没有条件预处理器宏。我无法避免包含有问题的标头,因为它包含插件所需的 2000 行以上代码。我无法将提供的分配器传递到其他库中,因为它没有为此提供任何机制。我已经就此向供应商进行了窃听。我不知道我还能尝试什么?
附录:经过一番激烈的争论,我成功说服供应商从下一版本的 SDK 中再次删除重载。我通过简单地破解当前的 SDK 并手动删除重载就解决了眼前的问题。感谢本线程中的所有建议。它们作为论据和进一步的“证据”证明了为什么重载首先是一个坏主意。
I'm maintaining a plugin (implemented as a dll) for a big closed source application. This has been working fine for years. However, with the latest update to it's SDK the vendor overloaded global operators new and delete. This causes lots of trouble for me. What happens is that my plugin allocates a string. I pass this string into a statically linked library which modifies it (changes it's length thus reallocating it). My application crashes.
The reason is of course, that the string lives on the vendor allocated custom heap. The statically linked library knows nothing about this heap and tries to use the default new/delete operators on that memory. Boom.
Now the question is: how can I keep my code clean and avoid using the vendor's operators? There is no conditional preprocessor macro. I can not avoid including the offending header since it contains 2000 lines more code I need for the plugin. I cannot pass the provided allocator into the other library since it does not provide any mechanisms for that. I have already bugged the vendor about it. I don't know what else I could try?
Addendum: After some heated debate I have managed to convince the vendor to remove the overloads again from the next version of the SDK. I have solved my immediate problem by simply hacking the current SDK and removing the overloads manually. Thanks for all the suggestions in this thread. They served as arguments and further "proof" of why the overloads were a bad idea in the first place.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您正在编译(通过标头包含)覆盖的 new/delete 运算符,则代码中对 new/delete 的所有调用都将使用它们。无法重新覆盖它(链接错误)或仅部分覆盖它等。
覆盖全局 new/delete 运算符根本不是一种好的形式。这是一个坏主意。如果你不明白为什么这是一个坏主意,你就没有资格这样做。如果您确实意识到为什么这是一个坏主意,那么您就有资格这样做,但您通常会选择不这样做。
在您期望人们直接包含到他们的项目中的组件中,定义全局新建/删除是指数级的邪恶。作为客户,您的工作是帮助供应商了解情况的严重性,或者停止成为他们的客户。
您可以定义自定义分配器类型(请参阅此链接一个很好的教程,介绍如何做到这一点、所需的接口等)并将其专门用于您的 STL 类型(它是一个模板参数)。
对于shared_ptr,您需要做一些不同的事情:如果您不想要默认的“delete p”行为,它会将删除器对象作为构造函数的参数。这不是一个自定义分配器;它只是一个常规的一元函子。
If you're compiling in (via header inclusion) an overridden new/delete operator(s), then all calls in your code to new/delete will use them. There is no way to re-override it (link errors) or only partially override it, etc.
It is bad form to override the global new/delete operators, at all. It's a bad idea. If you don't realize why it's a bad idea, you're not qualified to do so. If you do realize why it's a bad idea, you're qualified to do so, but you'll generally choose not to.
Defining a global new/delete is exponentially more evil in a component you expect people to include directly into their project. It is your job as a customer to help the vendor doing this understand the seriousness of the situation, or stop being their customer.
You can define a custom allocator type (see this link for a good tutorial on how to do so, the interface needed, etc) and use that exclusively with your STL types (it's a template argument).
For shared_ptr, you need to do something a little different: it takes a deleter object as a parameter to the constructor if you don't want the default "delete p" behavior. This isn't a custom allocator; it's just a regular unary functor.
是不是可以这样做:
那么evil_header声明为全局new/delete的内容就变成evil::new/evil::delete。不过,我怀疑如果在villain_header中声明的东西有非标头定义的话,这会发挥很好的作用。
Isn't it possible to do this:
Then what evil_header declares as global new/delete becomes evil::new/evil::delete. I doubt this will play well if there are non-header definitions of things declared in evil_header though.
您可以在命名空间中使用另一个新的:
然后您可以使用所有 STL 类,将您的分配器类型作为模板参数。
You can use another new in your namespace:
Your can then use all STL classes, giving them your allocator type as template argument.
一种选择是创建您自己的重载 new 运算符,该运算符可以根据 malloc 来实现。
可以这样定义:
然后您可以将其调用为
MyClass* myClass = new (EMyNew)MyClass;
由于这是根据 malloc 实现的,因此它的行为应该符合预期。唯一的缺点是您必须替换所有使用过新实例的实例。
One option is to create your own overloaded new operator that can be implemented in terms of malloc.
This could be defined like:
This can then be called by you as
MyClass* myClass = new (EMyNew)MyClass;
Since this is implemented in terms of malloc, it should behave as expected. The only downer is that you will have to replace all the instances of where you have used new.