2

I want to change a vector. I don't know whether it would be better to change the vector per reference or to return a copy. Is the additional copy operation (necessary for the version with the return) optimized out by avr gcc? What is the better practice?

inline void wrap180_Vec3f(Vector3f &vec) {
  vec.x = vec.x < -180.f ? (vec.x + 360.f) : (vec.x > 180.f ? (vec.x - 360.f) : vec.x);
  vec.y = vec.y < -180.f ? (vec.y + 360.f) : (vec.y > 180.f ? (vec.y - 360.f) : vec.y);
  vec.z = vec.z < -180.f ? (vec.z + 360.f) : (vec.z > 180.f ? (vec.z - 360.f) : vec.z);
}

Or

inline Vector3f wrap180_Vec3f(Vector3f vec) {
  vec.x = vec.x < -180.f ? (vec.x + 360.f) : (vec.x > 180.f ? (vec.x - 360.f) : vec.x);
  vec.y = vec.y < -180.f ? (vec.y + 360.f) : (vec.y > 180.f ? (vec.y - 360.f) : vec.y);
  vec.z = vec.z < -180.f ? (vec.z + 360.f) : (vec.z > 180.f ? (vec.z - 360.f) : vec.z);
  return vec;
}
dgrat
  • 2,214
  • 4
  • 24
  • 46
  • Floating point 3D using C++ on the AVR? Cool! :) – unwind Mar 05 '14 at 10:46
  • 2
    You cannot pass `Vector3f &vec` to a function in `C`. Either remove `C` tag or simply use the second way. – 0xF1 Mar 05 '14 at 10:46
  • 1
    Depends on the semantics you want. Is this a mutator? Or a function to obtain a new vector? See also: `+` vs `+=`. And pick _one_ language, please. – Lightness Races in Orbit Mar 05 '14 at 10:47
  • (Deleted my answer since I have no intimate knowledge of AVR. I *think* it’s still correct but I haven’t got the time now to find out if – for whatever reason – avr-gcc doesn’t do RVO. – Konrad Rudolph Mar 05 '14 at 10:48
  • It depends very much on the use-cases you have, and your overall design. – Some programmer dude Mar 05 '14 at 10:48
  • Also, if it was me creating the second version, I would have made it take a `const` reference argument, and have a local variable inside the function which I assigned to and returned. – Some programmer dude Mar 05 '14 at 10:50
  • 1
    **when in doubt, measure** – Karoly Horvath Mar 05 '14 at 10:53
  • Take by `const` reference, copy it, return the copy. – juanchopanza Mar 05 '14 at 10:53
  • @juanchopanza I suggested the same and got a downvote. – concept3d Mar 05 '14 at 10:54
  • @concept3d I saw that and up-voted. – juanchopanza Mar 05 '14 at 10:55
  • @MadHatter I removed the 'C' tag. – unwind Mar 05 '14 at 10:57
  • There is no best solution, you have to measure it on your target platform, the result is architecture/compiler dependent. For example in case of CryEngine it was a subject of debate whether to use Vec3 by value or Vec3 reference return values: One of them was winner on a specific platform while the other solution was better on the others. BTW, In this case I would opt for the return value because it results in more readable code where you use it and today's compilers do very good job at inlining and optimizing away things. – pasztorpisti Mar 05 '14 at 11:20
  • I also think it would be better readable with return value. I also think, that the compiler could be potentially able to optimize it. But I don't understand how and why it can be faster than a reference alone! – dgrat Mar 05 '14 at 11:34

3 Answers3

0

I would pass by reference and use a return. It gives the compiler the oppurtuninty to do some optimizations such as return value optimization or moving the object. it's also more readable without inspecting the function signature.

For example

Vector3f v= wrap180_Vec3f( vec );

// is more readable than

wrap180_Vec3f(v); 

Though if your intent is to modify an existing object use a reference.

concept3d
  • 2,248
  • 12
  • 21
0

It is obvious that passing the vector by reference is the fastest approach compared with passing the vector by value and returning it also by value. Moreover in the last case you again need to assign the original vector by the returned vector. This includes numerous calls of constructors and copy/move assignment operators of the vector itself and of its elements.

For such compound objects the best practice is to pass them by reference if you need to change them or pass them by const reference if you are not going to change them.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Actually its not obvious, because you have missed the point of the "inline". The call to the function is never being made. – Myforwik Mar 05 '14 at 10:54
  • 1
    @Myforwik Even if a function is inline constructors and assignment operators are used. – Vlad from Moscow Mar 05 '14 at 10:56
  • I agree that this is not obvious. 1) the function is supposed to be inlined 2) all members are being changed. I really would like to see a comparison of the assembly. – pmr Mar 05 '14 at 10:56
  • @pmr Using specifier inline does not guarantee that the function will be inlined. And again if a function is inline it doed not mean that copies of objects that passed by value will not be created. – Vlad from Moscow Mar 05 '14 at 10:58
0

On an AVR it would be insanity to do anything except pass by reference.

Unless you know how the compiler inline's exactly you end up possibly using up CPU cycles, as without the inline, or with a poor compiler implementation of it, the stack/heap will be used more.

Also I am not sure you code makes any sense did you mean:

inline void wrap180_Vec3f(Vector3f *vec) {
  vec->x = vec->x < -180.f ? (vec->x + 360.f) : (vec->x > 180.f ? (vec->x - 360.f) : vec->x);
  vec->y = vec->y < -180.f ? (vec->y + 360.f) : (vec->y > 180.f ? (vec->y - 360.f) : vec->y);
  vec->z = vec->z < -180.f ? (vec->z + 360.f) : (vec->z > 180.f ? (vec->z - 360.f) : vec->z);
}
Myforwik
  • 3,438
  • 5
  • 35
  • 42