Это не совсем ответ, просто ответ на комментарий, который слишком длинный для другого комментария, и он имеет отношение к этому вопросу.
Пожалуйста, не используйте Singleton.Ваша заявленная причина для этого заключается в том, что вы будете использовать ее для хранения информации о конфигурации, и эта информация о конфигурации должна быть доступна из любой точки программы.
Это причина (хотя, ИМХО, не обязательноотличный вариант) для глобальной переменной, но не причина для синглтона.Какой вред существует в более чем одном объекте, который хранит существующую конфигурацию?Если бы все пользователи использовали глобальную переменную для доступа к ней, они все использовали бы одну и ту же.Почему полезно принудительно ограничивать количество экземпляров до одного?
Во-вторых, что произойдет в будущем, когда вам потребуется временно добавить некоторые параметры конфигурации?Скажем, каким-то образом ваша программа должна быть запущена как подпрограмма или что-то с немного другой информацией о конфигурации, а затем восстановить исходную конфигурацию?Или, может быть, вам нужно несколько раз изменить конфигурацию для тестирования, а затем восстановить ее в исходное состояние?С Singleton и глобальной переменной это становится очень сложно.Но если вы использовали что-то более гибкое, это довольно тривиально.
Теперь лично я думаю, что передача параметров конфигурации всем вещам, которые нуждаются в них явным образом, не обязательно является плохим способом.Но если вы считаете, что это недопустимо, вот альтернатива:
template <typename T>
class DynamicallyScoped {
public:
explicit DynamicallyScoped(T &stackinstance) : oldinstance_(0) {
oldinstance_ = S_curinstance;
S_curinstance = &stackinstance;
}
~DynamicallyScoped() {
S_curinstance = oldinstance_;
oldinstance_ = 0;
}
static T *curInstance() { return S_curinstance; }
private:
static T *S_curinstance;
T *oldinstance_;
// Made private and left undefined on purpose.
DynamicallyScoped(const DynamicallyScoped &b);
const DynamicallyScoped &operator =(const DynamicallyScoped &b);
};
Это позволяет вам заменить текущий экземпляр для области и автоматически восстановить его, когда эта область исчезнет.И это также позволяет вам говорить DynamicallyScoped<Foo>::curInstance()->get_something();
в любом месте вашей программы, кроме конструкторов для статических или глобальных объектов, и ожидать получить что-то полезное.
Это каракули, и, вероятно, полезное в этой форме.Но я могу представить, как это может быть лучше.Например, с некоторой модификацией вы можете иметь несколько динамически изменяемых переменных одного и того же типа.
Пример использования:
#include <iostream>
template <>
int *DynamicallyScoped<int>::S_curinstance = 0;
extern void doSomething();
extern void doSomethingElse();
extern void printTheInt();
int main(int argc, char *argv[])
{
int x = 5;
DynamicallyScoped<int> theInt(x);
printTheInt();
doSomething();
doSomethingElse();
}
void doSomething()
{
printTheInt();
}
void doSomethingElse()
{
int newint = 6;
DynamicallyScoped<int> subint(newint);
doSomething();
}
void printTheInt()
{
::std::cout << "_The_ integer's value is: "
<< *DynamicallyScoped<int>::curInstance() << '\n';
}
Что касается беспокойства о том, что больше экземпляров вашего "глобального файла конфигурации"объект может быть создан, не жестко закодируйте имя файла.Создайте объект в main
как переменную стека и дайте ему имя файла в качестве аргумента.Тогда не будет проблем, если другие части кода создадут экземпляры объекта файла конфигурации, если они также не дадут имя файла глобальной конфигурации.И если они это делают, они заслуживают того, что получают.