библиотека вызывает глобальные перегрузки нового / удаления на меня! - PullRequest
5 голосов
/ 05 января 2010

Я поддерживаю плагин (реализованный как dll) для большого приложения с закрытым исходным кодом. Это работало хорошо в течение многих лет. Однако с последним обновлением его SDK поставщик перегружен глобальными операторами new и delete. Это доставляет мне много хлопот. Что происходит, так это то, что мой плагин выделяет строку. Я передаю эту строку в статически связанную библиотеку, которая изменяет ее (изменяет ее длину, перераспределяя ее). Мое приложение вылетает.

Причина, конечно, в том, что строка живет в выделенной куче поставщика. Статически связанная библиотека ничего не знает об этой куче и пытается использовать операторы new / delete по умолчанию в этой памяти. Boom.

Теперь вопрос: как я могу сохранить свой код в чистоте и избежать использования операторов поставщика? Условного макроса препроцессора не существует. Я не могу избежать включения заголовка, который нарушает работу, так как он содержит на 2000 строк больше кода, необходимого для плагина. Я не могу передать предоставленный распределитель в другую библиотеку, так как она не предоставляет никаких механизмов для этого. Я уже прослушал продавца об этом. Я не знаю, что еще я мог попробовать?

Приложение: После некоторых горячих споров мне удалось убедить поставщика снова снять перегрузки со следующей версии SDK. Я решил свою непосредственную проблему, просто взломав текущий SDK и сняв перегрузки вручную. Спасибо за все предложения в этой теме. Они послужили аргументами и дополнительным «доказательством» того, почему перегрузки были плохой идеей.

Ответы [ 4 ]

4 голосов
/ 05 января 2010

Если вы компилируете (посредством включения заголовка) переопределенные операторы new / delete, то все вызовы в вашем коде для new / delete будут использовать их. Нет способа переопределить его (ошибки ссылки) или только частично переопределить его и т. Д.

Плохо переопределять глобальные операторы new / delete. Это плохая идея. Если вы не понимаете, почему это плохая идея, вы не можете это сделать. Если вы понимаете, почему это плохая идея, вы можете это сделать, но в целом вы решите не делать этого.

Определение глобального new / delete экспоненциально больше зла в компоненте, который, как вы ожидаете, люди будут включать непосредственно в свой проект. Ваша работа как клиента заключается в том, чтобы помочь продавцу, понимающему серьезность ситуации, или перестать быть его клиентом.

Вы можете определить пользовательский тип распределителя (см. Ссылку для хорошего учебника о том, как это сделать, необходимый интерфейс и т. Д.) И использовать его исключительно с вашими типами STL (это аргумент шаблона). ,

Для shared_ptr вам нужно сделать что-то немного другое: он принимает объект-конструктор в качестве параметра для конструктора, если вам не нужно поведение по умолчанию "delete p". Это не пользовательский распределитель; это обычный унарный функтор.

2 голосов
/ 05 января 2010

Разве нельзя сделать это:

namespace evil{

#include "evil_header.h"

}

Тогда то, что evil_header объявляет глобальным new / delete, становится evil :: new / evil :: delete. Я сомневаюсь, что это будет хорошо работать, если в злом заголовке есть определения вещей, которые не указаны в заголовке.

1 голос
/ 05 января 2010

Вы можете использовать другое новое в вашем пространстве имен:

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, указав им тип распределителя в качестве аргумента шаблона.

0 голосов
/ 05 января 2010

Одним из вариантов является создание собственного перегруженного нового оператора, который может быть реализован в терминах malloc.

Это можно определить как:

enum MyNew {EMyNew};

void *operator new(size_t size, MyNew);

Это может быть названо вами как MyClass* myClass = new (EMyNew)MyClass;

Так как это реализовано в терминах malloc, оно должно вести себя как ожидалось. Единственным недостатком является то, что вам придется заменить все экземпляры, где вы использовали новые.

...