• Returning Multiple Values
    35 replies, posted
I'm trying to think of the best way to do this. For a function I need to return the resolution, as width, height, bits and fullscreen. How could I do this?
Use a structure. [cpp] struct { int width; int height; int bits; bool fullscreen; } mystruct; void myfunction() { mystruct.width = GetSystemMeterics(CX_SCREENX); //something like this //carry on } [/cpp] Most likly completly wrong, havnt touched C for ages.
return a struct?
That means I'd have to have like.. 2 more structures in total. This could pile up to eventually be 50 structures. Won't that hurt my code or some crap?
Another way to do it is to pass pointers to the function and have the function put data in them. In fact I believe this is the best and fastest way to do it.
An example would be nice.
You can also use references, like so.. [cpp] void MyFunc( int& a, int& b ) { a = 1; b = 2; } [/cpp]
Returning structs is actually kind of messy and usually discouraged. The correct way is to pass "out" parameters, basically pointers to memory you've allocated yourself: [cpp] #include <stdio.h> /*In C, you could return an int determining success or error instead of void (same convention as the main function)*/ void someFunc(int* a, int* b) { *a = 1; *b = 2; } int main() { int a, b; someFunc(&a, &b); printf("a: %d\tb: %d\n", a, b); return 0; } [/cpp] In C++, you should use references for this: [cpp] #include <iostream> void someFunc(int& a, int& b) { a = 1; b = 2; } int main() { int a, b; someFunc(a, b); std::cout << "a: " << a << "\tb: " << b << std::endl; return 0; } [/cpp] Finally, how to do it with a struct: [cpp] #include <iostream> struct A { int a, b; }; void someFunc(A& s) { s.a = 1; s.b = 2; } int main() { A s; someFunc(s); std::cout << "a: " << s.a << "\tb: " << s.b << std::endl; return 0; } [/cpp] edit: Feel free to ask if you have any questions about my examples.
Or you could return a struct: [cpp] #include <iostream> struct A { int a,b; }; A someFunc() { A struct_A; struct_A.a = 2; struct_A.b = 1; return struct_A; } int main() { A struct_B = someFunc(); return 0; } [/cpp] (Based of what I remember, not tested)
In Objective-C, you can create an object internally and pass it out as long as you follow the memory management convention - which is to tack on a retain, as autorelease pools are drained every event cycle if you're writing Cocoa apps.
[QUOTE=Mattz333;16976871]Or you could return a struct: -snip-[/QUOTE] Returning structs/classes by value is usually discouraged. Firstly, you don't get to decide where to allocate the struct, it's inevitably dumped on the stack. Secondly, you can't return an integer determining success or error (not a problem if you use exceptions). Thirdly, it means you'll need a second copy of the struct within the function, which makes for difficult optimization, as the struct will be allocated on the stack twice (and copied once), which also adds a lot of implicit code. If you then decide you wanted the struct on the heap, suddenly 3 copies of the struct will have existed before you're done with it.
[code] int bits; layer->getResolution(0, 0, bits, 0);[/code] [code]..\..\Jengine3D\include\IEngineLayer.h|88|note: candidates are: virtual void JE3D::IEngineLayer::getResolution(int&, int&, int&, bool&)|[/code] I want to only get able to get one.
References must refer to something. You probably want a pointer that you check for NULL before assigning. That, or you should realize width(), height(), numBits() and isFullscreen() would be more appropriate.
[code] //! Sets the values passed to the variable wanted for the resolution. virtual void getResolution(int &resolutionWidth, int &resolutionHeight, int &resolutionBits, bool &resolutionFullscreen) { if(resolutionWidth != 0) resolutionWidth = width; if(resolutionHeight != 0) resolutionHeight = height; if(resolutionBits != 0) resolutionBits = bits; if(resolutionFullscreen != 0) resolutionFullscreen = fullscreen; }[/code]
You can't do that (like I said), you need to use pointers.
-snip- Actually, now that I think about it, just make the fields public, or make separate getter functions for every field.
[QUOTE=HubmaN;16976968]In Objective-C, you can create an object internally and pass it out as long as you follow the memory management convention - which is to tack on a retain, as autorelease pools are drained every event cycle if you're writing Cocoa apps.[/QUOTE] Not always, you only need to use retain if you use a function that returns an autoreleased object. If you use something like [cpp][[NSArray alloc] init][/cpp] you will just have to release the object manually later.
pointers
Return an int array with all the values in it?
save it to a text file then load it again
[QUOTE=Mattz333;16984587]Return an int array with all the values in it?[/QUOTE] Not a good idea. The only way you could do this is return a new array allocated on the heap. And that is just slow and dumb. Remember that if you have an array declared on the stack in some function, then it is invalid to access that array again once you return from the function. [editline]02:57PM[/editline] The easiest and best way to do this is to give pointers as arguments to the function. The function fills those memory locations with good stuff.
[QUOTE=cracka;16981398]Not always, you only need to use retain if you use a function that returns an autoreleased object. If you use something like [cpp][[NSArray alloc] init][/cpp] you will just have to release the object manually later.[/QUOTE] But don't the convenience functions (i.e. [NSArray arrayWithObjects:[NSNumber yada...], nil] ), return an autoreleased object, though? I'm assuming that's what he'd do here.
Holy shit, so many over technical answers. Just make the variables public to whatever scope they need to be used, and assign them in the function. Screw all that pointer bullshit, boo hoo if it uses a whole extra couple bytes worth of memory for a nanosecond that it takes to copy it and delete it. When you need to do this for something big though, like a texture/sound/map/anything over 1KB, do it by pointers.
[QUOTE=jivemasta;16996638]Holy shit, so many over technical answers. Just make the variables public to whatever scope they need to be used, and assign them in the function. Screw all that pointer bullshit, boo hoo if it uses a whole extra couple bytes worth of memory for a nanosecond that it takes to copy it and delete it. When you need to do this for something big though, like a texture/sound/map/anything over 1KB, do it by pointers.[/QUOTE] Doesn't that kind of defeat the purpose of writing a function in the first place? The purpose of being able to use the same function in a multitude of locations and situations?
[QUOTE=jivemasta;16996638]Screw all that pointer bullshit, boo hoo if it uses a whole extra couple bytes worth of memory for a nanosecond that it takes to copy it and delete it. When you need to do this for something big though, like a texture/sound/map/anything over 1KB, do it by pointers.[/QUOTE] What are you talking about?
[QUOTE=jA_cOp;16996857]What are you talking about?[/QUOTE] Dude up there was saying that passing a struct or whatever is going to have 3 copies on the heap. Which will amount to(in this use) only a few wasted bits of memory for a fraction of a second until the stack resolves and clears all that out and leaves the original struct with the new values. It won't matter for just plain stuff like integers and stuff like that, but once you get into games, it could possibly run out of memory if you have 3 or 4 versions of a large texture or file floating around doing nothing. That's when you'd probably want to use a pointer, so you are directly changing the memory instead of copying it rewriting it and deleting it. As for the other comment, yeah it defeats the purpose of a reusable function, if you are going to reuse it, you might as well return a struct or use the pointer way if you are using c/c++.
[QUOTE=jivemasta;16997942]Dude up there was saying that passing a struct or whatever is going to have 3 copies on the heap.[/QUOTE] That was me, except I said 2 on the stack and then possibly one on the heap if that's where you needed it. The other day, some guy posted code with a class containing arrays (structs often have string buffers in C), bringing the size up to almost 400 bytes per instance. It's not a memory problem, but if run in a loop, it's a lot of unnecessary copying, when you could be writing the struct to the final location from the beginning. That was the least important reason I stated anyway. [QUOTE=jivemasta;16997942]Which will amount to(in this use) only a few wasted bits of memory for a fraction of a second until the stack resolves and clears all that out and leaves the original struct with the new values.[/QUOTE] Or, we could be consistent, and use the same good practices throughout the program. One solution is to have a private struct in the class containing the width, height, bits and fullscreen fields, then a getter function returning a constant reference to that struct. That way you can have the fields read-only while not having to use pointers, just like having a getter function per field.
If you're changing the width, height, bit depth and whatever else in a loop, you're doing something very wrong. Returning a struct would be just fine for this - If you don't want the copy that you'll never notice anyway, then pass it by reference after initializing it on the stack before the function call. This is a gross case of useless optimization versus ease of use. But the best solution remains having separate functions for each parameter, like nullsquared suggested.
[QUOTE=HubmaN;16996392]But don't the convenience functions (i.e. [NSArray arrayWithObjects:[NSNumber yada...], nil] ), return an autoreleased object, though? I'm assuming that's what he'd do here.[/QUOTE] That's what I said. Functions like [NSArray new] or [[NSArray alloc] init] don't return an autoreleased object.
[QUOTE=cracka;17003165]That's what I said. Functions like [NSArray new] or [[NSArray alloc] init] don't return an autoreleased object.[/QUOTE] Oh. Er. :ninja: I need to review the memory contract more.
Sorry, you need to Log In to post a reply to this thread.