визуальная реализация Singleton с использованием класса Friend (C ++)

Я придумал это, пытаясь создать синглтон.
Пример: (Я пытаюсь сделать 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 должно быть? и где это должно быть инициализировано?

3

Решение

нет, но это не основная проблема.

Инициализация глобальных объектов (таких как static) неупорядочен по единицам перевода; Это означает, что если во время создания одного глобального я звонил MySingleton::GetInstance() Я мог бы закончить указателем на унифицированную память.

Увидеть Заказ инициализации Fiasco.

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

В общем, рекомендуется использовать синглтон Мейера:

MySelf& MySelf::Instance() { static MySelf S; return S; }

который обходит фиаско порядка инициализации двумя способами:

  • гарантируется, что объект будет инициализирован при Instance() возвращается
  • Начиная с C ++ 11 и далее, компиляторы обязаны обрабатывать код инициализации таким образом, чтобы во время инициализации обнаруживался повторный вход (gcc уже делал в C ++ 03)

Более того, начиная с C ++ 11, он должен быть поточно-ориентированным, то есть вызывать другой поток. Instance() в то время как объект создается, он будет терпеливо ждать окончания построения и затем возвращать тот же экземпляр, что и все другие потоки (gcc уже делал в C ++ 03).

Примечание: использование постороннего класса просто больше печатать без добавленной стоимости, угробите это.

6

Другие решения

Вот более простая реализация:

template <class T>
class GenericSingleton
{
public:
static T& GetInstance()
{
static T _instance;
return _instance;
}
};

Это также потокобезопасный в C ++ 11, потому что статическая переменная создается перед любым потоком.

5

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector