Re: References vs variables - speed impacts?
On 7 Nov, 16:20, Nick Hounsome <nick.houns...@googlemail.com> wrote:
On 5 Nov, 18:47, Rune Allnor <all...@tele.ntnu.no> wrote:
Hi all.
I always thought references were mere synonym names to already
existing variables;
size_t long_and_complicated_expression;
size_t& i = long_and_complicated_expression;
Instead of typing the long and complicated name, one gets away
with the short and sweet 'i'.
In the code I am working with now, references appear to behave
as if they were actual variable assignments. Consider the nested
vector indexes
std::vector<size_t> v1;
std::vector<size_t> v2;
size_t n;
{// Unconditional evaluation
const size_t& i = v1[v2[n]];
const size_t& j = v2[v1[n]];
This effectively does something like:
size_t* const j = &( v1.operator[]( v2.operator[]( n ) ) ); //
calling T& vector<T>::operator[](size_t);
NOT
#define j v2[v1[n]]
The cost of this obviously far from 0 but will depend on what checking
you have enabled and how much the compiler can/will inline the calls.
It seem this is the crux. I reviewed the code, and found two
possible (and very likely) obstacles to removal of temporary
variables, which I depend on the compiler to do for me:
1) Type casts. The vector contains objects of that contain
a number of size_t pointers to other elements:
class element{
const size_t a() const; // Read element a
const size_t b() const;
const size_t c() const;
void a(const size_t&); // Modify element a
void b(const size_t&);
void c(const size_t&);
private:
size_t a_;
size_t b_;
size_t c_;
};
First of all, I use const T& as argument type by default
in function calls, so I use the const size_t& signature in
the modifying functions as a matter of course, not speed
reasons.
With the signatures above, the layered element access
through temporary object goes like
size_t k,m,n;
std::vector<element> v;
size_t tmp = v[n].a();
v[k].b(tmp);
As far as I can tell, the typecast of tmp that happens in
the call to element::b(const size_t&), from size_t to size_t&,
might be enough to stop the optimizer from optimizing the
temporary variable tmp away from the executable code.
2) Changing const elements. I declare my temporary variables
like
const size_t& tmp1 = v[n].a();
const size_t& tmp2 = v[m].b();
const size_t& tmp3 = v[k].c();
Then I start modifying the elements:
// Use tmp1
// The *value* referred to tmp1 is now obsolete, and
// never used again. The *variable* referred to by
// tmp1 will be modified:
tmp3 = v[tmp2].c();
v[n].a(tmp3); // << === element referred to by tmp1
// changes here
I didn't realize it when I coded up these things, but I
assume such constructs put too much strain on the optimizer,
so it might be more likely to back down, leaving the code as
written, instead of attempting to do the optimizations I
need it to do.
If any of these hypotheses are close to what actually happens,
it would explain why explicit calls without temporary variables,
like
v[n].a(v[m].b()); // In the actual code there can be 3-5 nested
// layers of dereferences, both in the index
// indicated by 'n' here, and in the argument
// to the modifyer function. Which makes the
// code unreadable. Which is why I wanted to
// use the temporaries, but with somewhat more
// descriptive names than indicated above.
execute orders of magnitudes faster: This call is explicit,
unequivocal, and can easily be optimized whithout the
optimizer having to impose unwarranted assumptions on the
use of the code.
Rune
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]