Is it safe to return a struct in C or C++?
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?
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).
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.
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.
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.
It's perfectly legal, but with large structs there are two factors that need to be taken into consideration: speed and stack size.