Reputation: 91
This is my Vector struct: struct Vector{ float x, y; };
const Vector&
?Upvotes: 9
Views: 4793
Reputation: 44503
I really depends on your platform and compiler, and whether the function is inline or not.
When passed by reference, the structure is not copied, only its address is stored on the stack, not the content. When passed by value, the content is copied. On a 64-bit platform the size of the struct is the same as a pointer to the struct (assuming 64-bit pointers which seems to be the more common situation). So, the gains of passing by reference is not really clear here.
However, there is another thing to consider. Your structure contains float value. On Intel architecture, they can be stored in the FPU or in SIMD register before the call to the function. In that situation, if the function take the parameter by reference, then, they will have to be spilled to memory, and the address to this memory passed to the function. This can be really slow. If they had been passed by value, no copy to memory would be needed (faster). And one some platform (PS3), the compiler will not be smart enough to remove those spilling, even in case of inline function.
In fact, like every question of micro-optimisation, there is no "good answer", it all depends on what usage you make of the function, and what your compiler / platform want. The best would be to mesure (or use a tool to analyse assembly) to check what is the best for your platform / compiler combination.
I'm going to finish by quoting Jaymin Kessler from Q-Games that is much more versed in those topics than I can ever be:
2) If a type fits in a register, pass it by value. DO NOT PASS VECTOR TYPES BY REFERENCE, ESPECIALLY CONST REFERENCE. If the function ends up getting inlined, GCC occasionally will go to memory when it hits the reference. I’ll say it again: If the type you are using fits in registers (float, int, or vector) do not pass it to the function by anything but value. In the case of non-sane compilers like Visual Studio for x86, it can’t maintain the alignment of objects on the stack, and therefore objects that have align directives must be passed to functions by reference. This may be fixed or the Xbox 360. If you are multiplatform, the best thing you can do is make a parameter passing typedef to avoid having to cater to the lowest common denominator.
Considering the following code:
struct Vector { float x, y; };
extern Vector DoSomething1(Vector v);
extern Vector DoSomething2(const Vector& v);
void Test1()
{
Vector v0 = { 1., 2. };
Vector v1 = DoSomething1(v0);
}
void Test2()
{
Vector v0 = { 1., 2. };
Vector v1 = DoSomething2(v0);
}
From the point of view of the code, the only difference between Test1
and Test2
is the calling convention used by DoSomething1
and DoSomething2
to receive the Vector
struct. When compiled with g++
(version 4.2, architecture x86_64), the generated code is:
.globl __Z5Test1v
__Z5Test1v:
LFB2:
movabsq $4611686019492741120, %rax
movd %rax, %xmm0
jmp __Z12DoSomething16Vector
LFE2:
.globl __Z5Test2v
__Z5Test2v:
LFB3:
subq $24, %rsp
LCFI0:
movl $0x3f800000, (%rsp)
movl $0x40000000, 4(%rsp)
movq %rsp, %rdi
call __Z12DoSomething2RK6Vector
addq $24, %rsp
ret
LFE3:
We can see that in the case of Test1
, the value are passed via the %xmm0
SIMD register once loaded from memory (so if they where the result of a previous computation, they would already be in the register and there would be no need to load them from memory). On the other hand, in the case of Test2
, the value are passed on the stack (movl $0x3f800000, (%rsp)
push 1.0f
on the stack). And if they where the result of a previous computation, that would require copying them from the %xmm0
SIMD register. And that can be really slow (it may well stall the pipeline until the value is available, and if the stack is not properly aligned, the copy will also be slow).
So if your function is not inline, prefer to pass by copy instead of const-reference. If the function is indeed inline, watch the code generated before making your mind.
Upvotes: 3
Reputation: 206699
If you pass by value, the function will get a copy that it can modify locally without affecting the caller.
If you pass by const-reference, the function will only get a read-only reference. No copying involved, but the called function cannot modify it locally.
Given the size of the struct, the copy overhead will be very small. So choose what is best/easiest for the called function.
Upvotes: 10
Reputation: 67193
As a reference. That is more efficient than making a copy of the structure and passing that (i.e. passing by value).
The only exception is if your platform can fit the entire structure into a register.
Upvotes: 0
Reputation: 363567
For such a small structure, either one may be the most efficient, depending on your platform and compiler.
(The name may be a bit confusing to other programmers, since vector in C++ usually means "dynamic array". How's about Vector2D
?)
Upvotes: 7