Я придумал это, пытаясь создать синглтон.
Пример: (Я пытаюсь сделать MySelf
синглтон, который является потокобезопасным и не использует двойной контроль блокировки)
class MySelf
{
private:
string Name;
int Age;
MySelf()
{
Name = "Deamonpog";
Age = 24;
cout << "Constructing MySelf : " << Name << endl;
};
friend class MySingleton;
public:
~MySelf(){ cout << "Destructing MySelf : " << Name << endl; };
int MyAge() const
{
return Age;
}
};
class MySingleton
{
private:
static MySelf mself;
public:
static MySelf * GetInstance()
{
return &mself;
}
};
MySelf MySingleton::mself;
Теперь я могу легко использовать это как,
cout << "I am " << MySingleton::GetInstance()->MyAge() << endl;
Я не хочу ленивой инициализации, потому что класс, который я собираюсь создать, будет там от начала до конца. Но безопасен ли этот поток? (насколько мне известно, это нормально)
Если это нормально, тогда я должен использовать общее программирование, как это,
template <class T>
class GenericSingleton
{
private:
static T _instance;
public:
static T * GetInstance()
{
return &_instance;
}
};
template <class T>
T GenericSingleton<T>::_instance;
Так что я могу использовать это с любым другим классом тоже. и мне просто нужно добавить friend class GenericSingleton<MySelf>;
на нужный сиглет (например, на класс MySelf).
Может ли эта реализация вызвать проблемы? Я на самом деле создаю библиотеку. Некоторые синглтоны должны быть экспортированы, а некоторые нет. И что делать, если это не для библиотеки, а просто для другого приложения?
— РЕДАКТИРОВАТЬ —
Так что теперь я должен сделать это так (так как я использую VC ++, который все еще не поддерживает C ++ 11),
static MySelf & GetInstance()
{
WaitForMutex(mymutex); // some function from the threading library
if( NULL == _instance )
{
_instance = new MySelf();
}
ReleaseMutex(mymutex); // release function of the same library
Return _instance;
}
И попросите пользователя использовать функцию один раз и затем кешировать ее для использования.
(Или я также могу переименовать функцию в Initialize()
и создайте другой метод для простого возврата ссылки без какой-либо блокировки или создания. )
Так где же mymutex
должно быть? и где это должно быть инициализировано?
нет, но это не основная проблема.
Инициализация глобальных объектов (таких как static
) неупорядочен по единицам перевода; Это означает, что если во время создания одного глобального я звонил MySingleton::GetInstance()
Я мог бы закончить указателем на унифицированную память.
Увидеть Заказ инициализации Fiasco.
Кроме того, если бы мне нужно было запустить второй поток на этом этапе инициализации, он мог бы получить доступ к частично инициализированному объекту.
В общем, рекомендуется использовать синглтон Мейера:
MySelf& MySelf::Instance() { static MySelf S; return S; }
который обходит фиаско порядка инициализации двумя способами:
Instance()
возвращаетсяБолее того, начиная с C ++ 11, он должен быть поточно-ориентированным, то есть вызывать другой поток. Instance()
в то время как объект создается, он будет терпеливо ждать окончания построения и затем возвращать тот же экземпляр, что и все другие потоки (gcc уже делал в C ++ 03).
Примечание: использование постороннего класса просто больше печатать без добавленной стоимости, угробите это.
Вот более простая реализация:
template <class T>
class GenericSingleton
{
public:
static T& GetInstance()
{
static T _instance;
return _instance;
}
};
Это также потокобезопасный в C ++ 11, потому что статическая переменная создается перед любым потоком.