functions pointers for main loop, does anyone do that?

Hi,
i have a program's main loop performing different actions depending on it's "mode" (let's pretend the mode is just an integer from an enum).
These actions are repeated many times, while the mode changes rarely; then, instead of checking the mode variable every single time the loop occurs, i thought why not just put a function pointer there, and change the pointer to a different function when mode changes?

Now my question is, does anyone do that or i'm just being totally crazy?

It's a perfectly reasonable solution, although if mode changes rarely I would consider making control flow match program state. So, instead of
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void loop(){
    while (active){
        switch (mode){
            case 0:
                run0();
                break;
            case 1:
                run1();
                break;
            //...
        }
    }
}

void run0(){
    //do something and return immediately
}
I would do
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void loop(){
    while (active){
        switch (mode){
            case 0:
                mode0();
                break;
            case 1:
                mode1();
                break;
            //...
        }
    }
}

void mode0(){
    while (active && mode == 0){
        //do something
    }
}
This is generally easier for the CPU cache and branch predictor to handle.
what i'm doing does use function pointers: (i'm not using c++ syntax now, just pseudocode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
void action_1a()
	{
	//do stuff
	}
void action_2a()
	{
	//do stuff
	if(something happens)
		{
		set_mode(b);
		}
	}
void action_3a()
	{
	//do stuff
	}

void action_1b()
	{
	//do stuff
	}
void action_2b()
	{
	//do stuff
	if(something happens)
		{
		set_mode(a);
		}
	}
void action_3b()
	{
	//do stuff
	}

function pointer acion_1;
function pointer acion_2;
function pointer acion_3;

enum mode_type {a, b};

void set_mode(mode_type mode)
	{
	switch(mode)
		{
		case a:
			action_1 = &action_1a;
			action_2 = &action_2a;
			action_3 = &action_3a;
			break;
			
		case b:
			action_1 = &action_1b;
			action_2 = &action_2b;
			action_3 = &action_3b;
			break;
		}
	}

int main()
	{
	while(active)
		{
		(*action_1)();
		//do stuff that doesnt depend on the mode
		(*action_2)();
		//do stuff that doesnt depend on the mode
		(*action_3)();
		}
	
	return(0);
	}
Last edited on
Hmm... I don't know... I don't like that three separate things have to be set correctly in order to perform a mode change. That looks like a copy-paste error waiting to happen.
Is there any way to put the mode-independent bits in functions, so that you merge those functions into
1
2
3
4
5
6
7
void action_a(){
    //part 1
    mode_independent_1();
    //part 2
    mode_independent_2();
    //part 3
}
?

Your code looks slightly coroutiney, but that's probably overkill.
Something like this, perhaps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
struct mode
{
    virtual mode* action_1() = 0 ;
    virtual mode* action_2() = 0 ;
    virtual mode* action_3() = 0 ;
    // ...

    void mode_independent_x() { /* do mode_independent stuff */ }
    void mode_independent_y() { /* do mode_independent stuff */ }
};

extern mode* a ;
extern mode* b ;

struct mode_a : mode
{
    virtual mode* action_1() override { /* do mode_a stuff */ return this ; }
    virtual mode* action_2() override { /* do mode_a stuff */ return some_condition ? b : this ; }
    virtual mode* action_3() override { /* do mode_a stuff */ return this ; }
    // ...
} instance_mode_a;

struct mode_b : mode
{
    virtual mode* action_1() override { /* do mode_b stuff */ return some_condition ? a : this ; }
    virtual mode* action_2() override { /* do mode_b stuff */ return this ; }
    virtual mode* action_3() override { /* do mode_b stuff */ return some_condition ? a : this ; }
    // ...
} instance_mode_b;

mode* a = std::addressof(instance_mode_a);
mode* b = std::addressof(instance_mode_b);

int main()
{
    mode* current_mode = a ;

    while(active)
    {
        current_mode = current_mode->action_1() ;
        current_mode->mode_independent_x() ;
        current_mode = current_mode->action_2() ;
        current_mode->mode_independent_y() ;
        current_mode = current_mode->action_3() ;
    }
}

More information: https://sourcemaking.com/design_patterns/state
Topic archived. No new replies allowed.