Статические объекты и синглтоны - PullRequest
1 голос
/ 17 декабря 2010

Я использую Boost Singletons (из сериализации).

Например, есть некоторые классы, которые наследуют boost::serialization::singleton.Каждый из них имеет такое определение около своего определения (в h-файле):

#define appManager ApplicationManager::get_const_instance()
class ApplicationManager: public boost::serialization::singleton<ApplicationManager> { ... };

И мне нужно вызывать какой-то метод из этого класса каждое обновление (почти 17 мс), например, 200 раз.Код выглядит так:

for (int i=0; i < 200; ++i)
   appManager.get_some_var();

Я посмотрел gprof на стек вызовов функций и увидел, что boost::get_const_instance вызывает каждый раз.Может быть, компилятор в режиме релиза оптимизирует это?

Моя идея состоит в том, чтобы создать некоторую глобальную переменную, например:

ApplicationManager &handle = ApplicationManager::get_const_instance();

И использовать handle, чтобы она не вызывала get_const_instnace каждый раз.Это верно?

Ответы [ 4 ]

4 голосов
/ 17 декабря 2010

Вместо использования Singleton anti-pattern , просто глобальная переменная и покончим с этим. Это честнее.

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

Лично я думаю, что проекты с глобальными переменными или синглетонами почти наверняка сломаны. Но каждому h (является / er) свой.

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

ApplicationManager &myAppManager = appManager;
for (int i=0; i < 200; ++i)
   myAppManager.get_some_var();

Кстати, использование этого #define таким образом является серьезной ошибкой. Почти во всех случаях, когда вы используете препроцессор для чего-либо кроме условной компиляции, основанной на флагах времени компиляции, вероятно, плохое применение. Boost широко использует препроцессор, но в основном для того, чтобы обойти ограничения C ++. Не подражайте этому.

Наконец, эта функция, вероятно, выполняет что-то важное. Одна из задач метода get_instance для Singletons состоит в том, чтобы избежать одновременной инициализации несколькими потоками одного и того же Singleton. С глобальными переменными это не должно быть проблемой, потому что они должны быть инициализированы до того, как вы запустите какие-либо потоки.

2 голосов
/ 17 декабря 2010

Это действительно проблема?Я имею в виду, действительно ли ваше приложение страдает от такого поведения?

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

1 голос
/ 17 декабря 2010

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

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

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

1 голос
/ 17 декабря 2010

Да, это, безусловно, возможное решение.Я не совсем уверен, что делает повышение с его синглтоном за кулисами;Вы можете посмотреть это сами в коде.

Шаблон синглтона во многом похож на создание глобального объекта и доступ к глобальному объекту.Существуют некоторые различия:

1) Экземпляр синглтон-объекта не создается до тех пор, пока к нему не обращаются впервые, тогда как глобальный объект создается при запуске программы.2) Поскольку одноэлементный объект не создается до тех пор, пока к нему не обращаются в первый раз, он фактически создается при запуске программы.Таким образом, экземпляр singleton имеет доступ к другим полностью созданным объектам в программе, когда конструктор фактически работает.3) Поскольку вы обращаетесь к синглтону через метод getInstance () (метод get_const_instance boost), для выполнения вызова этого метода есть небольшие накладные расходы.

Так что если вас не интересует, когда на самом деле синглтонсозданный, и может жить с ним, создаваемым при запуске программы, вы можете просто использовать глобальную переменную и получить к ней доступ.Если вам действительно нужен синглтон, созданный после запуска программы, тогда вам нужен синглтон.В этом случае вы можете захватить и удерживать ссылку на объект, возвращаемый get_const_instance (), и использовать эту ссылку.

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

1) Не пишите код, который может привести к выполнению деструктора (скажем, с помощью общего указателя на возвращенную ссылку), или пишите любой другой код, который может вызвать объектв конечном итоге в плохом состоянии.

2) В многопоточном приложении позаботьтесь о правильной блокировке полей в объекте, если объект может использоваться более чем одним потоком.

3) В многопоточном приложении убедитесь, что все потоки, которые содержат ссылки на объект, завершаются до выгрузки программы.Я видел случай, когда код синглтона находится в одной библиотеке DLL;поток, содержащий ссылку, живет в другой библиотеке DLL.Когда программа заканчивается, поток все еще активен.DLL, содержащая код синглтона, была выгружена первой;поток, который был еще жив, пытался что-то сделать с объектом синглтона и вызвал сбой.

...