Is it safe to return a struct in C or C++?
Solution 1
It's perfectly safe, and it's not wrong to do so. Also: it does not vary by compiler.
Usually, when (like your example) your struct is not too big I would argue that this approach is even better than returning a malloc'ed structure (malloc
is an expensive operation).
Solution 2
It's perfectly safe.
You're returning by value. What would lead to undefined behavior is if you were returning by reference.
//safe
mystruct func(int c, int d){
mystruct retval;
retval.a = c;
retval.b = d;
return retval;
}
//undefined behavior
mystruct& func(int c, int d){
mystruct retval;
retval.a = c;
retval.b = d;
return retval;
}
The behavior of your snippet is perfectly valid and defined. It doesn't vary by compiler. It's ok!
Personally I always either return a pointer to a malloc'ed struct
You shouldn't. You should avoid dynamically allocated memory when possible.
or just do a pass by reference to the function and modify the values there.
This option is perfectly valid. It's a matter of choice. In general, you do this if you want to return something else from the function, while modifying the original struct.
Because my understanding is that once the scope of the function is over, whatever stack was used to allocate the structure can be overwritten
This is wrong. I meant, it's sort of correct, but you return a copy of the structure you create inside the function. Theoretically. In practice, RVO can and probably will occur. Read up on return value optimization. This means that although retval
appears to go out of scope when the function ends, it might actually be built in the calling context, to prevent the extra copy. This is an optimization the compiler is free to implement.
Solution 3
The lifetime of the mystruct
object in your function does indeed end when you leave the function. However, you are passing the object by value in the return statement. This means that the object is copied out of the function into the calling function. The original object is gone, but the copy lives on.
Solution 4
Not only it is safe to return a struct
in C (or a class
in C++, where struct
-s are actually class
-es with default public:
members), but a lot of software is doing that.
Of course, when returning a class
in C++, the language specifies that some destructor or moving constructor would be called, but there are many cases where this could be optimized by the compiler.
In addition, the Linux x86-64 ABI specifies that returning a struct
with two scalar (e.g. pointers, or long
) values is done thru registers (%rax
& %rdx
) so is very fast and efficient. So for that particular case it is probably faster to return such a two-scalar fields struct
than to do anything else (e.g. storing them into a pointer passed as argument).
Returning such a two-scalar field struct
is then a lot faster than malloc
-ing it and returning a pointer.
Solution 5
It's perfectly legal, but with large structs there are two factors that need to be taken into consideration: speed and stack size.
jzepeda
Updated on July 02, 2020Comments
-
jzepeda almost 4 years
What I understand is that this shouldn't be done, but I believe I've seen examples that do something like this (note code is not necessarily syntactically correct but the idea is there)
typedef struct{ int a,b; }mystruct;
And then here's a function
mystruct func(int c, int d){ mystruct retval; retval.a = c; retval.b = d; return retval; }
I understood that we should always return a pointer to a malloc'ed struct if we want to do something like this, but I'm positive I've seen examples that do something like this. Is this correct? Personally I always either return a pointer to a malloc'ed struct or just do a pass by reference to the function and modify the values there. (Because my understanding is that once the scope of the function is over, whatever stack was used to allocate the structure can be overwritten).
Let's add a second part to the question: Does this vary by compiler? If it does, then what is the behavior for the latest versions of compilers for desktops: gcc, g++ and Visual Studio?
Thoughts on the matter?
-
jzepeda about 12 yearsWould it still be safe if one of the fields was a char*? Now there would be pointer in the struct
-
Pablo Santa Cruz about 12 yearsYes, it would. Just be careful when you malloc/free that
char*
. -
Luchian Grigore about 12 yearsHeard of return value optimization?
-
Luchian Grigore about 12 years@user963258 actually, that depends on how you implement the copy constructor and destructor.
-
Captain Giraffe about 12 years@PabloSantaCruz That is a tricky question. If it was an exam question the examiner might well expect a "no" as a response, if ownership needs to be considered.
-
Pablo Santa Cruz about 12 years@CaptainGiraffe: true. Since OP didn't clarified this, and his/her examples were basically C, I assumed that it was more a C question than a C++ one.
-
Luchian Grigore about 12 years@CaptainGiraffe if I was asked this in an interview, I'd definetely say that it depends on how the two are implemented, not go for a straight "Yes".
-
ebutusov about 12 yearsYes, but we're speaking general of returning struct by value, and there are cases where the compiler is unable to perform RVO.
-
Luchian Grigore about 12 yearsI'd say only worry about the extra copy after you've done some profiling.
-
Kos about 12 yearsBut of course it varies by compiler! Some compilers have NRVO, some don't. And if a compiler doesn't (and by any reason you can't trash it to make place for a more recent one), then you might want to consider returning the struct by pointer "out" parameter instead.
-
Kos about 12 years+1 for mentioning RVO. This important optimization actually makes this pattern feasible for objects with expensive copy constructors, like STL containers.
-
David about 12 years@Kos Some compilers don't have NRVO? From what year? Also to note: In C++11 even if it doesn't have NRVO it will invoke move semantics instead.
-
damianostre about 12 yearsAn original K&C "compliant" compiler doesn't support returning structs that are bigger than an "int"'s size, IIRC. @user963258: The returned struct will be copied usually over the stack, meaning that if the struct is huge, you might run out of stack space (only really relevant on embedded systems, though). The data will be copied the same way as if you'd have a "&" or "*" argument and would copy the data in your function that way. That means: if the struct contains pointers, the pointers get copied, but not what the pointers point to, of course.
-
damianostre about 12 yearsThe stack is only used temporarily for the copy operation. Usually, the stack would get reserved before the call, and the called function puts the to-be-returned data onto the stack, and then the caller pulls this data from the stack and stores it whereever it gets assigned to. So, no worries there.
-
Necrolis about 12 yearsActually, it does vary by compiler, GCC requires an extension (under x86-32) to return structs the same as MSVC does, due to differences in the ABI used, see: gcc.gnu.org/bugzilla/show_bug.cgi?id=36834
-
Watcom over 11 yearsIt's worth mentioning that although the compiler is free to perform return value optimization, there's no guarantee it will. This is not something you can count on, only hope.
-
Steve over 9 yearsWould still be safe to return a vector of these structs ?
-
Jonathan Leffler about 9 yearsIt would be more helpful if you gave a pointer to the Wine mailing list that you're referring to.
-
M.M over 8 yearsReturning structs is fine. COM specifies a binary interface ; if someone doesn't implement COM properly then that would be a bug.
-
Braden Best almost 8 yearsSafe, sure, but with the ability to return structs, I can do retarded stuff like this:
struct func { struct func (*fn)(); }; ... struct func why(){ return (struct func){why}; } ... struct func wow = why().fn().fn().fn().fn().fn().fn().fn...;
, which is way more amusing than it should be. Not even a peep from-Wall -pedantic
. -
phg over 6 years“It is not safe to return a structure. […] the copy constructor will be called.” – There’s a difference between safe and inefficient. Returning a struct is definitely safe. Even then, the call to the copy ctor will most likely be elided by the compiler as the struct is created on the caller’s stack to begin with.
-
Lloyd Sargent over 4 years-1 for "avoiding dynamically allocated memory when possible.” This tends to be a newb rule and frequently results in code where LARGE amounts of data is returned (and they puzzle why things run slowly) when a simple pointer can save a lot of time. The correct rule is return structures or pointers based on speed, usage, and clarity.
-
Björn Sundin almost 4 yearsOnly true before c++11.
-
Mox almost 4 yearsinteresting facts.I think golang has something similar.