
Mathias Gaunard wrote:
Ion GaztaƱaga wrote:
That was a change in the forwarding code. Since perfect forwarding can't be achieved in C++03
Really? Can't you just overload all the possible const/non-const combinations? That would surely do forwarding of constness just fine. Of course, this is only feasible if you have few arguments.
Until recently, I thought that the "perfect forwarding" problem was a technical defect of C++03, but then I read through the following: Robert Jones wrote:
There's a terrific article about RVO and copy elision by Dave A at
somewhere down, we have the following Dave Abrahams wrote:
One place you can apply this guideline immediately is in assignment operators. The canonical, easy-to-write, always-correct, strong-guarantee, copy-and-swap assignment operator is often seen written this way:
T& T::operator=(T const& x) // x is a reference to the source { T tmp(x); // copy construction of tmp does the hard work swap(*this, tmp); // trade our resources for tmp's return *this; // our (old) resources get destroyed with tmp }
but in light of copy elision, that formulation is glaringly inefficient! It's now "obvious" that the correct way to write a copy-and-swap assignment is:
T& operator=(T x) // x is a copy of the source; hard work already done { swap(*this, x); // trade our resources for x's return *this; // our (old) resources get destroyed with x }
Reality Bites
So operator= takes "T x" as an argument, but if the function that want to forward its arguments also takes "T x" as argument and passes "x" as argument to operator=, neither RVO nor "copy elision" can help. So something called "rvalues" could be introduced in an attempt to help, let's write it as "T&& x". But at which point in time should the destructor of x now be called? The implementation of operator= probably wants to rely on the fact that the destructor of x gets called upon exit from operator=. But if the destructor of x should also be called upon exist of the function that forwarded x, we must create at least one additional x object so that we have room for two destructor calls. The other alternative is that operator= takes its argument as "T&& x", but now it can no longer rely on the fact that the destructor of x gets called upon exit from operator=. So operator= must now worry about the resources owned by x upon exit, and possibly try to free them. So it is unclear to me whether the "perfect forwarding" problem is solvable at all. Regards, Thomas