1

Тема: Ініціалізація статичних членів класу функцією.

Доброго часу доби!
Подібний код вдало компілюється за допомогою Visual Studio та g++, та чи відповідає він стандарту?

SomeClass SomeFunction (int, int);

class A
{
public:
   static SameClass element;
};
SameClass A::element = SomeFunction(0, 0);

   На жаль мені не вдалось знайти відповідь на це питання у книзі Страуструпа, він тільки зазначає, що статичне поле/функція має бути описане в класі і визначене у глобальній області видимості, а от чи можна для цього використовувати виклик довільної функції - ні слова.
   Отже чи вірно я розумію, що так робити можна і поле element буде гарантовано ініціалізовано правильним значенням ще до створення першого об’єкту класу А?

2

Re: Ініціалізація статичних членів класу функцією.

Стандарт вимагає визначення поля. Операція присвоєння - наступний етап, який може і не наставати ніколи, а може настати і безпосередньо у глобальній області. Головне, щоб функція на момент виконання вже існувала і була видною.
А взагалі - недобре так робити: ліпше ініціалізувати у main(). :)

3

Re: Ініціалізація статичних членів класу функцією.

Страуструп показує ось так в своїй книзі.

task* task::task_chain = 0;

Тому, якщо можна, поясніть детальніше стосовно того, що присвоєння може і не настати ніколи. А також і чому так робити не бажано.

припустімо, що я намагаюсь зробити такий синглтон

Прихований текст
 
#include <WinBase.h>

class Singleton
{
public:
   static Singleton* getInstance();
private:
   static Singleton *_instance;
   static HANDLE InitialLock;
   Singleton();
};

Singleton* Singleton::_instance = 0;
HANDLE Singleton::InitalLock = CreateMutex(NULL, false, "SingletonLock");
..........

тоді виходячи з Вашої поради мені потрібно замінити рядок:

HANDLE Singleton::InitalLock = CreateMutex(NULL, false, "SingletonLock");

наступним

HANDLE Singleton::InitalLock;

і додати в мій main() рядок:

Singleton::initialLock = CreateMutex(NULL, false, "SingletonLock");

у випадку з одним класом такого типу - все в принципі окей, але якщо синглтонів потрібно кілька то, на мою думку, це вже буде не зручно створювати для кожного мютекс в функції main().
Чи іншого вибору в мене немає?

4

Re: Ініціалізація статичних членів класу функцією.

присвоєння може і не настати ніколи

Може і не настати. Скажімо, якщо ініціалізація та використання м'ютекса залежить від якихось умов (параметру в argv, наприклад), то і нічого його ініціалізувати явно.

чому так робити не бажано

Бо main() є точкою входу, а глобальна ініціалізація, по ходу, виконується до входження у main().

у випадку з одним класом такого типу - все в принципі окей, але якщо синглтонів потрібно кілька то, на мою думку, це вже буде не зручно створювати для кожного мютекс в функції main().
Чи іншого вибору в мене немає?

Якщо у вас є статичний член-м'ютекс, то хто заважає додати статичний метод, який ініціалізуватиме його?

5

Re: Ініціалізація статичних членів класу функцією.

Bartash написав:

Бо main() є точкою входу, а глобальна ініціалізація, по ходу, виконується до входження у main().

Статичні поля-змінні класу ініціалізуються до створення першого об'єкту цього класу. Власне цю властивість я і хотів використати для того, аби не мати необхідності руками ініціалізувати мютекс для перевірки в функції:

Singleton* Singleton::_getInstance()
{
  if (!_instance)
  {
    WaitForSingleObject(InitialLock, INFINITE);
    if ( !_instance)
    {
      _instance = new Singleton;
    }
    ReleaseMutex(InitialLock);
  }
  return _instance;
}

отже я все ще не можу збагнути - дозволено так робити, не дозволено чи просто не бажано.

6

Re: Ініціалізація статичних членів класу функцією.

Andy написав:

отже я все ще не можу збагнути - дозволено так робити, не дозволено чи просто не бажано.

Дозволено. Але обережно з WaitForSingleObject() при INFINITE - не отримайте ненароком deadlock.

Якщо вам потрібна глобальна змінна типу цього Сінглтона, логічніше буде так:

//main.cpp
#include "mysingleton.h"

Singleton *s;

int main()
{
    s = Singleton::_getInstance();
    if(s) //Якщо відмовитеся раптом від INFINITE
    {}//працюєте далі
//...
return 0;
}