[Linux] Problem z singletonem Meyersa

0

Otóż, piszemy aplikację na wiele platform i stosujemy singletony Meyersa w następujący sposób:

GeneralController.cpp:

GeneralController::GeneralController(void)
{
ArffFormat::StartProduce();
StructureManager::getInstance().discretizeFunction =
&DiscretizingMethods::simplyDiscretization;

  DiscretizingMethods::SimplyDiscretization::numberOfIntervals=20;
  nmbArguments = 8;
  nmbRows = 40;
  nmbTrees = 10;

}

GeneralController& randomforest::getInstance()
{
static GeneralController instance;
return instance;
}

I teraz problematyczny StructureManager (nie tworzy obiektu, w debuggerze okazuje się, że próbuje 2 razy stworzyć obiekt, ale ponieważ jest singletonem- jest ok. Poza tym - nie wchodzi do konstruktora!!

StructureManager& randomforest::StructureManager::getInstance()
	{
		static StructureManager StructureInstance;
		return StructureInstance;
	}

	StructureManager::StructureManager()
	{
		workers=0;
		stage = INTRODUCTION;
	}

O ile kod działa pod VS 2008, nie działa pod linuxem (kompiluje się bez problemu, a potem no właśnie... Zatrzymuje się na pierwszej linijce StructureManager getInstance, bez żadnego komunikatu o błędach. Pomoże ktoś?

0

Problem jest taki, że za dużo masz tych singletonów, a na dodatek one zależą od siebie.

        GeneralController& randomforest::GeneralController::getInstance()
        {
                static GeneralController instance; // tu masz problem
                return instance;
        }

StructureManager& randomforest::StructureManager::getInstance()
        {
                static StructureManager StructureInstance; // tu masz problem
                return StructureInstance;
        }

Tutaj nie masz zdefiniowanej kolejności tworzenia tych zmiennych statycznych, więc nie wiadomo, która zmienna zostanie zainicjowana jako pierwsza (to, że są wewnątrz metod nie ma żadnego znaczenia, lokalne zmienne statyczne są inicjowane tak jak zmienne globalne, jeszcze przed wywołaniem main). Z visual'em miałeś po prostu szczęście, że kolejność tworzenia singletonów jest właściwa.
Prawda jest taka, że lepiej by było, by jeden singleton tworzył i niszczył instancję drugiego na stercie, wtedy pozbędziesz się tego problemu, bo będziesz miał kontrolę nad kolejnością konstruktorów, albo jeszcze lepiej zastanów się czy nie przekombinowałeś struktury programu i ilości tych singletonów.

edit: w sumie jak na to jeszcze teraz patrzę, to to jest bardzo dziwne, że jeden singleton dokańcza inicjalizację drugiego singletona, za mało jednak widać kodu, by stwierdzić jakie były twoje intencje i czy na pewno to jest ten problem.

0

Dodałem jawne wywołanie ::getInstance dla każdego singletonu przed każdym możliwym użyciem, jednak nadal- debugger nie wchodzi między klamerki konstruktora, a jedynie na nazwę. Co dziwniejsze- konstruktor GeneralController'a jest wywoływany- z tamtego scope'a jest wywoływany getInstance dla StructureManagera. Kolejność wywołań (wg debuggera Eclipse) jest następująca:

main: MyMainWindow* w= new MyMainWindow();
MyMainWindow:

MyMainWindow::MyMainWindow(QWidget *parent, Qt::WFlags flags)
		: QMainWindow(parent, flags)
	{
		ui.setupUi(this);
		this->mySetupUi(this);
	}

...

void MyMainWindow::mySetupUi(QMainWindow *MyMainWindowClass)
	{

QObject::connect(
			&GeneralController::getInstance(),
			SIGNAL(sendMessage(QString)),
			this, 
			SLOT(actionDialogMessage(QString))
		);

GeneralController:

	GeneralController& GeneralController::getInstance()
	{
		static GeneralController instance;
		return instance;
	}

...

	GeneralController::GeneralController(void)
	{
		ArffFormat::StartProduce();
		StructureManager::getInstance().discretizeFunction = 
			&DiscretizingMethods::SimplyDiscretization::simplyDiscretization;

		DiscretizingMethods::SimplyDiscretization::numberOfIntervals=20;
		nmbArguments = 8;
		nmbRows = 40;
		nmbTrees = 10;
	}

StructureManager:

	StructureManager& StructureManager::getInstance()
	{
		static StructureManager StructureInstance;
		return StructureInstance;
	}

... i tutaj nie wchodzi w klamerki konstruktora, aczkolwiek wywołuje:

	StructureManager::StructureManager()
	{
		workers=0;
		stage = INTRODUCTION;
	}
0

sprawdz, czy PO wykonaniu linii ktora mialaby wywolac ctora, workers faktycznie ==0, a stage faktycznie == INTRO. postaw bpx'a, dodaj wypis tych watosci do logu itp.

Jezeli tak bedzie, to oznaczac moze, ze optymalizator wycial kod tego ctora jako bezznaczenia. Moglo sie tak stac np. gdy enum/const INTRO wynosi 0 -- jezeli kompiltor zerowalby wczesniej automatycznie wszystkie pola, to moglby wykryc ze ten kod niczego nie zmienia i w ogole wyciac wolanie ctora. W debugerze dokladnie tak by to wygladalo: dochodzisz do linii, dajesz step-into, a tu nic, program leci dalej: NIE MA nic do czego moglby zrobic step-in. Z tego co mi swita, wlasnie g++ pod linuksem domyslnie wszystkie inicjowane bloki pamieci zeruje, wiec jest to bardzo prawdopodobne. Jednak -- bedize to oznaczac, ze bald jest gdzies indziej, bo tam i tak po brakujacym ctorze wychodza poprawnie zera.

1 użytkowników online, w tym zalogowanych: 0, gości: 1