Boost logo

Boost :

From: John Maddock (John_Maddock_at_[hidden])
Date: 1999-11-30 07:57:56


Howard -

>So I'm now looking for an example where pass by (const) value (for a
small and fast type) is demonstrably superior to pass by const reference.<

I've been experimenting with fill_n (or rather a variation thereof), and
builtin types:

template <class T>
void fill_n1(T* out, std::size_t n, const T& t)
{
   while(n--)
   {
      *out = t;
      ++out;
   }
}

template <class T>
void fill_n2(T* out, std::size_t n, const T t)
{
   while(n--)
   {
      *out = t;
      ++out;
   }
}

called using:

    int i1 = 2;
    int j1 = 3;
    fill_n1(&i1, 1, j1);
    fill_n2(&i1, 1, j1);
    fill_n1(&i1, 1, 0);
    fill_n2(&i1, 1, 0);

    __int64 i2;
    __int64 j2 = 0;
    fill_n1(&i2, 1, j2);
    fill_n2(&i2, 1, j2);
    fill_n1(&i2, 1, 0i64);
    fill_n2(&i2, 1, 0i64);

with C++ Builder 4.

The assembly output makes the following comments worth while:

For int, pass by value/pass by reference have almost identical assembly for
the call, unless the argument is an immediate value:

   ; fill_n1(&i1, 1, 0);
   ;
        xor eax,eax
        mov dword ptr [ebp-476],eax
        lea edx,dword ptr [ebp-476]
        push edx
        push 1
        lea ecx,dword ptr [ebp-460]
        push ecx
        call @@%fill_n1$i%$qpiuirxi$v
        add esp,12
   ;
   ; fill_n2(&i1, 1, 0);
   ;
        lea eax,dword ptr [ebp-460]
        push 0
        push 1
        push eax
        call @@%fill_n2$i%$qpiuixi$v
        add esp,12

So here the by-value clearly wins, I think it may be a reasonably common
usage for some functions also.

Within the body of the function, pass by value is marginally better (the
code stores the value in a register, rather than a pointer to the value in
a register):

;by reference:
?live16441_at_16: ; EAX = out, EDX = n, ECX = t
@361:
        mov ebx,dword ptr [ecx]
        mov dword ptr [eax],ebx
        add eax,4

;by value:
?live16442_at_16: ; EAX = out, EDX = n, ECX = t
@365:
        mov dword ptr [eax],ecx
        add eax,4

For 64 bit ints the situation is more marginal:

within the body of the function the value never gets put in a register
(although this may be different on other processors), so the two forms are
the same (both cache a pointer to the __int64).

For calling - the by reference wins (by one instruction) if the value is
already on the stack, otherwise the call by value wins (by one instruction)
if the value is an immediate. Make of this what you will!

Whatever, passing builtin integral types by value is never really any worse
than pass by reference, and is sometimes optimal (at least on this
compiler).

Hope this helps.

- John.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk