Создание нескольких экземпляров глобальной статики в C ++? - PullRequest
4 голосов
/ 30 мая 2009

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

Instance* getInstance() {
    static Instance* inst = new Instance();
    return inst;
}

В таких ситуациях есть ли способ надежно создать больше, чем один экземпляр? Единственное, о чем я могу думать, - это не просто обрабатывать и использовать какой-то тип IPC, чтобы связать все это вместе. Я не могу придумать ничего менее хакерского.

Я попросил поставщика внедрить некоторый тип токена сеанса, чтобы я мог иметь несколько одновременных экземпляров, но они большие, а мы маленькие.

Cory

Edit:

  • машина является Windows-машиной
  • глобальная статика - это в основном большая фабрика. Мне нужен какой-то токен сеанса, чтобы я мог легко сказать «освободить все ресурсы из этого сеанса» (нет способа повторно инициализировать известную мне глобальную статику)

Вместо того, чтобы попробовать какие-нибудь хитрые махинации, чтобы получить то, что я хочу, я собираюсь обернуть все это своим собственным классом и добавить ключ сеанса к каждому получателю. Внутренне я буду следить за тем, что было выделено, и добавлю свой собственный метод выпуска для возврата ресурсов. Это неоптимально по многим причинам, но я не могу придумать лучшей идеи.

Спасибо всем за отличную обратную связь.

Ответы [ 5 ]

5 голосов
/ 30 мая 2009

Даже если бы вы смогли решить эту конкретную проблему, в то время как все происходило в процессе, я бы беспокоился, что эта проблема синглтона является лишь верхушкой айсберга. Библиотека явно не была разработана для вашего сценария.

Изоляция каждой загрузки DLL в отдельный процесс звучит для меня правильно и не хакерски, хотя, конечно, это может быть дорого для вас.

4 голосов
/ 30 мая 2009

К сожалению, я не вижу недостатка в ваших рассуждениях. Продавец принял решение, и вы связаны им. Он выбрал один экземпляр для каждого процесса, поэтому, если вам нужно несколько экземпляров, у вас должно быть несколько процессов со всеми вытекающими последствиями.

Конечно, если вы предполагаете, что его решение об ограничении является произвольным, и что для этого нет веских оснований, вы можете попытаться взломать его. Чтобы начать с этого пути, нужно выполнить пошаговую разборку / сборку в отладчике. Если вы можете подтвердить, что его фабрика экземпляров работает точно так же, как вы сделали вывод выше, вы, без сомнения, можете взломать альтернативу, которая позволяет создавать несколько экземпляров.

Но, конечно, огромный риск при таком подходе состоит в том, что каждая строка кода в кодовой базе поставщика, которая полагается на его решение иметь единственный экземпляр, становится бомбой замедленного действия, готовой взорваться вам в лицо. Этот код невидим для вас. Готовы ли вы поспорить, что таких линий ноль? Я знаю, что сказал бы Клинт Иствуд в такой ситуации; "Ты чувствуешь себя счастливчиком, хорошо?" : -)

2 голосов
/ 30 мая 2009

Не существует элегантных способов иметь несколько экземпляров одноэлементного объекта в одном программном пространстве - но это специально. Как правило, вы используете одиночный код только в том случае, если нежелательно иметь несколько экземпляров. Если поставщик реализовал свой продукт с использованием синглтона, для этого могут быть веские причины.

Возможно, если вы опишите вашу проблему более подробно, возможны другие подходы. Трудно сказать, исходя из предоставленной информации. Что делает одноэлементный объект? Зачем вам нужно несколько его экземпляров?

1 голос
/ 30 мая 2009

Единственное, о чем я могу подумать - это подкласс, если вам повезло, что класс синглтона определен как:

class Document {
public:
    static Document* getInstance() {
        static Document inst;
        return &inst;
    }
    virtual ~Document();
protected:
    Document();
private:
    struct Impl;
    Impl *pImpl;
};

Если вы можете создать его подкласс, и у подкласса будет доступ к конструктору, тогда вы можете создать экземплярный подкласс, например:

class MyDocument: public Document {
public:
    MyDocument(): Document() {
    }
};

Это может быть не совсем безопасно, так как разработчик мог сделать некоторые неприятные предположения. Но это идея или какой-то подход, который может иметь шанс на успех. Если вам повезет, продавец может подойти к этому варианту, если вы упомянули об этом ... удачи.

1 голос
/ 30 мая 2009

За исключением того, что вы предложили для межпроцессного процесса, лучший хак, который я могу придумать, это скопировать dll в новый файл и вручную загрузить новый dll и импортировать все функции, которые вы используете для каждого создаваемого вами экземпляра.

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

...