passing via object vs passing via return

I have two short code examples here. I am instantiating a class and using it to return the sum of two numbers. One pass back the result as a variable in its class content. The other passes back the result as a return from the enclosed function.
They both work. Is one to be preferred? I show and arduino here but I run things like this on other microprocessors so memory conservation is important.

Thanks
Fritz

============ passing with return ===============
#include <stdlib.h>
#include <string.h>
#include <Arduino.h>

class test1
{
public:
int a;
int b;
int c;
int adder(void)
{
c=a+b;
return(c);
} //end adder
}; //end class

test1 T;
int q;

void setup()
{
Serial.begin(9600);
} //end setup

void loop()
{
T.a = 3;
T.b = 5;
q = T.adder();
Serial.println(q);
} //end loop

================= passing in class variables ===================
#include <stdlib.h>
#include <string.h>
#include <Arduino.h>

class test1
{
public:
int a;
int b;
int c;
void adder(void)
{
c=a+b;
} //end adder
}; //end class

test1 T;

void setup()
{
Serial.begin(9600);
} //end setup

void loop()
{
T.a = 3;
T.b = 5;
T.adder();
Serial.println(T.c);
} //end loop

Please format your code.
https://www.cplusplus.com/articles/jEywvCM9/

After 10 posts, you should know this.
IMO, neither example is preferred.
The first example requires an extra step to assign the result to q before printing.
Why is c a member of Test1? It's not needed.
Here is how I would do it:
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
#include <stdlib.h>
#include <string.h>
#include <Arduino.h>

class test1
{
public:
	int a;
	int b;
	int adder(void)
	{
		return a + b;
	} //end adder
}; //end class

test1	T;
int		q;
void setup()
{
	Serial.begin(9600);
} //end setup

void loop()
{
	T.a = 3;
	T.b = 5;
	q = T.adder();
	Serial.println(q);
} //end loop 


PLEASE ALWAYS USE CODE TAGS (the <> formatting button) when posting code.
It makes it easier to read your code and also easier to respond to your post.
http://www.cplusplus.com/articles/jEywvCM9/
Hint: You can edit your post, highlight your code and press the <> formatting button.
the one with c is potentially doing more work because it stores the result in the class.
do you understand how the cpu registers and assembly level 'stack' (the thing that gets pushed and popped with function parameters when you call a function) work?
The q = adder one does not really need to keep q around. it can be a register only variable, and a smart compiler will spot that.
the class c one -- the example is so short maybe the optimizer will do the same, but odds are higher that it will do the extra assignment statement and shovel it back out of the cpu in a more complicated example.

these are tiny things you would not really care about -- the difference in the time taken in these examples is less than the margin of error in timing, so you can't even measure the difference with any certainty. If you want to know for sure if something like this is going on, you can force the compiler to show you the assembly language. Its a very, very small argument to favor the q= version.

And, on top of this, c in the class is clutter that increases the size of the object in memory and adds lines of code to it.

so, while its still just an opinion, I highly favor the q= version.
Thanks for the replies. Probably the example I used for simplicity is somewhat parochial and not the best example as far as demonstrating efficiency. But in the case of a larger subroutine with many more variables for example I would think it could matter. And in a lot of the calculations that one might do this routine could be accessed millions of times.
Jonnin-I am not clear on how the stack gets used here:
In conventional C on the few microprocessors that I have worked with, if variables are declared in the "main" routine they are allocated to the heap. In subsequent subroutine calls variables are allocated to the stack--which generally is from different memory routines. So in the case here I am not clear on there the memory for instantiation of the class is obtained -or where it is obtained from routines for this class.

Looking at these responses I gather there is no strong difference/preference in the two styles. Is there a "preferred" method with regards to C++ and OO conventions?

Thanks again
Fritz
I think, in your example, it does not really make sense to have a class for the "adder" functionality, which stores a and b (any maybe even the sum c) as member variables, because this could simply be implemented as a "stateless" function. Or, if you really want to wrap it in a class, then use a static member function:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Adder
{
public:
    static int add(const int a, const int b)
    {
        return a + b;
    }
};

int main()
{
    Serial.println(Adder::add(3, 5));
}


If, for whatever reason, you want to store a and b as member variables, then you should make them private, initialize them via your class' constructor, and provide the appropriate "getter" functions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Adder
{
public:
    Adder(const int a, const int b) : a(a), b(b) { }

    int getSum(void)
    {
        return a + b;
    }

private:
    const int a, b;
};

int main()
{
    Adder adder(3, 5);
    Serial.println(adder.getSum());
}


Or, if it is not necessary to separately keep the original a and b values:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Adder
{
public:
    Adder(const int a, const int b) : c(a + b) { }

    int getSum(void)
    {
        return c;
    }

private:
    const int c;
};
Last edited on
Its not the variable memory location I was talking about.
do you understand how parameters are passed to a function, results are passed back, and how long life span data is pulled from ram->cache->register and the reverse when it is assigned (register to cache to ram)? That copying from ram to cache to register costs you a blip of time and a couple of extra instructions. If you just did parameter passing, the data movement is different and more efficient -- it can either be left in a register and picked up by the caller or pushed and popped with the call stack, which is cheap compared to going in and out of ram.
Again all this is so microscopic as to be a non issue performance wise even on your embedded machine. But its there, and you asked :) This is NOT A GREAT REASON to do it the other way in general. its a classic case of worrying too much (premature optimizations) about something that (depending on the compiler and real code in play) may or may not even be happening (but it could, and you asked)

The more pressing issue is the clutter and odd design. Its just unusual (for no really good reason other than convention) to have a result of operations variable inside a class as a dumping ground.
That said, I have done similar to this and gotten a performance increase by doing so, but that was before c++ had copy elision ensured via the standard so I was doing something like your C technique to force elision and speed things along, using static variables. The code was not pretty, but it was very, very fast.

lets take it from here if you want to think deeper. "what is the problem you are trying to solve, really, with that C variable". Is it "I just think this way" and a style thing, or is there an end goal? Where do you end up if you have add, subtract, multiply, divide? Do you have 4 dump variables in the class, or one that is shared and its last state you have to follow through the code to know what was just done? What if you have a complicated math expression like a*(3*a+b/2) ... is that possible, and will your design hold up for it? Forget the performance nuances and convention of styles... justify the approach from extending your tools to do more stuff angle.
Last edited on
Looking at these responses I gather there is no strong difference/preference in the two styles.

In terms of performance, there is no measurable difference, in terms of "preferred" style, that is not what has been said.
As I replied earlier, neither of those approaches is "preferred" or good practice.
As jonnin explained, Best practice is to make a and b private and eliminate c.
However, I'm not familiar with the limitations of the Arduino or its compiler.
Last edited on
I think this stripped down code has taken a life of its own. In practice of course, the class could have numerous variables interacting in various was so there are reasons to store them in the class. In such a case I would think one would want to reserve the storage that they need.
Avoiding the code--the simple question is just:
"Should one pass back the variable as part of the class (e.g. T.c) or should one pass it back directly from a subroutine of that class via the subroutine return."

I guess from what I am reading there is no simple answer-both work-and it could depend upon circumstances. I just did not want to commit some gross violation of the OO philosophy in my method of coding this.

thanks
fs
I just did not want to commit some gross violation of the OO philosophy in my method of coding this.

Making the variables in the class public is a violation of the encapsulation principle.

Not knowing the Arduino I was concerned that the Arduino compiler was very limited in what it supported. However, a quick google reveals it uses gcc, so all the features of the C++ language are present. Therefore there is no reason not to observe the principle of encapsulation and make the variables private.

There are restrictions due to space on which libraries are supported, but that's not germane to this discussion.
I do not do much with Arduinos but the younger members of the team use them so I built this system on a "nano" so they can take it over. They are basically an ATMEL ATmeg328 and they did a pretty decent job. I helps to have read the ATMEL datasheets.
I am never clear on the gray area where the compiler software interfaces with the CPU hardware-I think some of the low level connections with memory may vary with the vendor but to delve into it I am getting way out of the area of interest for this project and may never see an arduino again. They did keep their IDE very simple (good!) but I one can run other IDEs (eclipse?) which give more thorough memory reporting etc.

Regarding public/private--I was not so concerned with this-more interested in whether "c" should be public and used from the class--or whether it should be passed via return. I have three C++ books sitting in my lab that are mute on this--probably a hint that I should not have asked. (:->

Thanks
f
"Should one pass back the variable as part of the class (e.g. T.c) or should one pass it back directly from a subroutine of that class via the subroutine return."

Really, as pointed out before, you should not store any "state" in member variables, unless there is a good reason why this is necessary. This applies to "input" parameters as well as to return values. So, if you can pass parameters directly into the function, and if you can return the result directly, then that is the way to go! The indirection of making your function read its "input" parameters from member variables, or making your function write its result into a member variable, should be avoided – unless there is a good reason to do otherwise.

Anyway, if you decide that your class needs to carry some "state" in its member variables, then you should implement a proper encapsulation. This means that you should make your member variables private and you also should initialize them in the constructor of your class. Add "getter" and "setter" functions as needed.

Examples: http://www.cplusplus.com/forum/beginner/283816/#msg1228862

In practice of course, the class could have numerous variables interacting in various was so there are reasons to store them in the class.

Yes, there can be good reasons to store member variables in the class.

But the question that you should always ask yourself is this: Is this variable a "state" of the object that needs to be maintained for the object's entire lifetime? If so, then a member variable is the right choice. If not, then this probably should be a direct function parameter, or a direct return value, not a member variable...
Last edited on
OK. That makes sense.
Thanks
fritz
Topic archived. No new replies allowed.