functions that return arrays, a question of style/philosophy

Hi,

I am a long-time user of Java/Processing and I’m doing some oF twiddling. I was porting a utility function over to C++ that converts an HSV value to RGB. I’m sure there is already some code somewhere out there to do this, but it feel likes a good exercise for me to get a better grasp of C++.

Anyway, it lead me to a question. The function needs to return an R, G and B value. There are a couple ways it seems like I could do this. One is to return an array that is created inside the function using the “new” keyword. Of course, then it is the responsibility of the caller to clear that array from memory using the “delete” keyword once its done with it, right?

The other option seems to be that the function is passed an array or pointers to individual floats R, G and B and just has a void return signature and sets these values where they already exist in memory. That way if the pointers passed in were created in a local scope, they are cleared from the stack right after they are used.

It seems to me like the second way is the ideal way to go, but maybe there is a third preferred way?

I’d love to get feedback from any seasoned C++ coders out there on how they like to treat a situation like this.

Thanks.

-Aaron

Usually with something as commonly associated as RGB you’d have a “color” class/struct which holds 3 values (OF might even have one), then you just need to return that and no additional management is needed by the caller.

this is the ugliest side of c/c++, establishing ownership of memory (and thus who frees it).

on a different note though, I have an advanced color class which handles conversions :stuck_out_tongue:

Smart pointers are really what you want! :wink:

Yes, exactly right. One problem here would be that your caller would not know the size of the array.

Yes, this is another good way to do it. As memo mentioned, you would need to be careful of overrunning your array bounds. A common solution to this is to pass both the array pointer (preallocated), as well as an int representing the size of the array.

The caller with still be responsible for correctly managing the memory. You would have the option of doing it dynamically (using new/delete), or just declaring an object, passing its address as a pointer and letting it be deallocated automatically when its scope dies.

A third way (and probably a best option), would be to do as Dingobloo suggests and use a specialized RGB struct or class. This would replace your array pointer with something a bit easier to interpret (color->r, vs colour[0]), but would still lead you to the previous two questions of how the object’s memory is managed. The advantage here is that your object’s size is predefined, so you would not need to worry about overrunning array bounds or anything like that.

In the end, when possible, using a custom class/struct is a better option than an array because it has predefined member’s instead of an unknown length. The choice of letting the function return a newly allocated object versus preallocating and passing a pointer is really depending on the situation and your coding style. I think in most cases I would take the second option (of preallocating and passing the pointer around), but in the case of an “addNewWidget” or factory/generator style method, I might take the first and just pass in a list of parameters needed for the newWidget’s construction.

For your HSV to RGB problem, because you’re using some data to generate other data, the first option might be a good choice. Something like

  
  
colorRGB* hsvToRGB(int h, int s, int v){  
  int r, g, b;  
  
  // perform HSV-RGB conversion here, setting function-scope r, g, b values  
  
  return new colorRGB(r, g, b);  // use calculated values to build a new colorRGB  
}  
  

A better approach might even be to encapsulate your HSV-RGB conversion right inside the colorRGB class… something like

  
  
class colorRGB{  
public:  
  int r, g, b;  
  
  colorRGB();  
  
  void setFromHSV(int h, int s, int v){  
    // perform HSV-RGB conversion here, setting class-scope r, g, b values  
  }  
};  
  

Pointers and memory management are usually one of the biggest challenges when learning C++ … especially if you’re coming from a Java background where garbage collection is all automatic.

One tip I would give you is that during development to always check your programs for memory leaks using a tool such as mallocDebug set to find leaks.

Hope this helps in some way…

I’d use a struct / class encapsulating the r,g and b values.

  
  
struct rgb_t { int r, g, b; };  
  
rgb_t hsvToRgb(int h, int s, int v)   
{   
  rgb_t rgb;  
  rgb.r = ..;  
  rgb.b = ...;  
  rgb.g = ...;  
  return rgb;  
}  
  

another possibility:

  
  
void rgbToHsv(int h, int s, int v, rgbt_& rgb) {  
  rgb.r = ..;  
  rgb.g = ..;  
  rgb.b = ..;  
}  
  

performance-wise the second option my be faster, but most compiler optimise the creation of the tempory object away. If you want to use your rgb-class with openGL then something like this will work

  
  
class rgb_t {  
private:  
 float rgb[3];  
public:  
  rgb_t(float r, float g, float b) { set(r,g,b); }  
  inline void set(float r, float g, float b) { rgb[0] = r; rgb[1] = g; rgb[2] = b; }  
  inline float* front() { return &rgb; }  
};  
  
rgb_t hsvToRgb(...) {  
  return rgb_t(r,g,b);  
}  
  
  

be aware of typos!

cheers,
Stephan

Thanks for all the advice. In the case of doing the color conversion, I thought having the data come in an array would be handy for stuffing into glColor3fv(), but since I’m working on the iPhone at the moment, it would appear that is not an option.

Anyway, if this function were running thousands of time every tick, would there be any kind of significant penalty from the overhead of allocating a struct versus the array? I have no sense for this, but generally in Java, I avoid creating new Objects whenever possible.

allocating a struct versus an array makes no difference whatsoever. Allocating objects (which are different than structs) can sometime have overhead if there are non-trivial initializations being done such as allocating large blocks of memory or computing some result that takes up a significant amount of time. In the case of colors, this isn’t going to be an issue.

The suggestion to include this in a general purpose color class is a good one. Also, you could create structs for these things

  
struct HSV {  
float h; float s; float v;  
};  
  
struct RGB {  
float r; float g; float b;  
};  

as has been pointed out. One can then use pass-by-reference to avoid allocating the memory and returning a struct as so:

  
void HSV2RGB(const HSV &hsv, RGB &rgb);  

I thought having the data come in an array would be handy for stuffing into glColor3fv()

You can still use glColor3fv with a struct

  
  
 ColorStruct myColor;  
  
 glColor3v((GLfloat*)&myColor);  
  

This is the beauty of the low level memory management of C. You are simply saying (reading right to left) ‘take the address of where my struct is, and now interpret it as a GLfloat*’
Of course it won’t work on iphone as you say cos of the lack of the glColor3v.

Anyway, if this function were running thousands of time every tick, would there be any kind of significant penalty from the overhead of allocating a struct versus the array?

Like otherside says there generally isn’t any difference between a struct and array allocation - unless the struct has a constructor. (Remember a struct in C++ is different to a typedef struct in C. The former is simply a class with default access set to public instead of protected, it can still have methods and constructors.)
However whether it be array or struct, allocating it thousands of times per tick should be avoided if you can, e.g. using a temp variable outside the loop to cache a temp preallocated space if possible. Especially on slower devices like iphone