Dzisiaj będzie o tym, jak napisać funkcję, która automatycznie wykona się  jeszcze zanim wystartuje funkcja main. Fajna sztuczka z dużym powerem. Zaczynamy!

Przykład

Do tego, aby funkcja odpaliła się na samym starcie aplikacji, wykorzystamy fakt, że zmienne globalne są inicjalizowane na samym początku, jeszcze przed uruchomieniem funkcji main :

#include <iostream>
using namespace std;

int initialize()
{
	cout << "aaa...jestem pierwsza!" << endl;
}

int dummy = initialize();

int main()
{
	cout << "funkcja main" << endl;
  	return 0;
}

Program po odpaleniu wyświetli nam:

	> aaa...jestem pierwsza!
	> funkcja main

Czyli nasza funkcja startuje wcześniej niż main :)

Wytłumaczenie

Globalna zmienna dummy ma tutaj tylko jedno zadanie – stać się przyczyną uruchomienia funkcji initialize.

Ponieważ  zmienne globalne zawsze są inicjalizowane przed uruchomieniem funkcji main, to musi też zostać zainicjalizowana nasza zmienna dummy. W tym celu zostanie wywołana nasza funkcja initialize, i… voila!

Zastosowanie

Przyjmijmy, że chcemy sobie napisać klasę Random, generującą liczby pseudolosowe w przedziale 0..1. Najwygodniej będzie chyba, jeśli zrobimy z niej klasę statyczną – w ten sposób będzie można wywoływać jej metody bez tworzenia obiektu. Który nie jest nam do niczego potrzebny. Pamiętasz pewnie, że generator liczb pseudolosowych musi zostać zainicjalizowany, jednokrotnie, przed pierwszym użyciem funkcji rand? Do tego właśnie celu wykorzystamy naszą samostartującą funkcję:

#include <cstdlib>
#include <ctime>

class Random
{
private:
	static int dummy;

	static int initialize()
	{
		srand(time(0));
		return 0;
	}

public:
	static double getDouble()
	{
		return (double) rand() / RAND_MAX;
	}
};

int Random::dummy = initialize();

Inicjalizacja składowej statycznej dummy wymusza uruchomienie prywatnej metody initialize, która z kolei inicjalizuje generator liczb pseudolosowych. W ten sposób nie musimy sami bawić się w inicjalizowanie generatora liczb – sprytny trick sprawi, że generator będzie zawsze zainicjalizowany w momencie startu aplikacji!

Wady

Wada jaka mi się nasuwa jest taka, że jeśli napiszemy drugą taką sprytną klasę z automatycznym inicjalizowaniem, to nie będziemy wiedzieć, który inicjalizator wystartuje pierwszy – brak gwarancji, że nasz Random będzie zainicjalizowany w chwili użycia.

Jeśli jakieś inne wady/zalety tej konstrukcji przychodzą Ci do głowy, a tym bardziej, jakieś ciekawe zastosowania – podziel się nimi w komentarzu!

Related Posts: