Pour me rappeler, je m'essai aux résumés.
* RVO = return-value optimization
MyData myFunction() {
return MyData(); // Create and return unnamed obj
}
MyData abc = myFunction();
With RVO, the C++ standard allows the compiler to skip the creation of the temporary, treating both object instances—the one inside the function and the one assigned to the variable outside the function—as the same. This usually goes under the name of copy elision. But what is elided here is the temporary and the copy.
MyData myFunction() {
MyData result; // Declare return val in ONE place
if (doing_something) {
return result; // Return same val everywhere
}
// Doing something else
return result; // Return same val everywhere
}
MyData abc = myFunction();
Named Return Value Optimization is similar but it allows the compiler to eliminate not just rvalues (temporaries), but lvalues (local variables), too, under certain conditions.
But many compilers are actualy failing to apply NRVO with the following code:
MyData myFunction() {
if (doing_something)
return MyData(); // RVO expected
MyData result;
// ...
return result; // NRVO expected
}
MyData abc = myFunction();
So previous example has to be preferred.
Surprisingly, don’t use "out-parameters" but prefer "return-by-value", even if it implies creating a small struct in order to return multiple values. I will check that, because it seems strange to me.
“out” parameter pointers force a modern compiler to avoid certain optimisations when calling non-inlined functions.
Prefer:
struct fractional_parts {
int numerator;
int denominator;
};
fractional_parts convertToFraction(double val) {
int numerator = /*calculation */ ;
int denominator = /*calculation */ ;
return {numerator, denominator}; // C++11 braced initialisation -> RVO
}
auto parts = convertToFraction(val);
use(parts.nominator);
use(parts.denominator);
than:
void convertToFraction(double val, int &numerator, int &denominator) {
numerator = /*calculation */ ;
denominator = /*calculation */ ;
}
int numerator, denominator;
convertToFraction(val, numerator, denominator); // or was it "denominator, nominator"?
use(numerator);
use(denominator);
Prefer:
template <class T>
complex<T> &complex<T>;::operator*=(const complex<T> &a) {
T a_real = a.real, a_imag = a.imag;
T t_real = real, t_imag = imag; // t == this
real = t_real * a_real – t_imag * a_imag;
imag = t_real * a_imag + t_imag * a_real;
return *this;
}
than:
template <class T>
complex<T> &complex<T>;::operator*=(const complex<T> &a) {
real = real * a.real – imag * a.imag;
imag = real * a.imag + imag * a.real;
return *this;
}
It seems the example is too simple to really understand the benefits. I do not want to make my code more complex for such a simple case... I do not like this advice.
Due to the CPU caches mechanisms (blocks of 64-byte), it is propose to organise member variables in a class as follow:
Why not...
Pour le coup, cet article n'ayant pas pour but d'expliquer RAII l'explique beaucoup mieux que d'autres.
Il va me falloir un peu de temps pour acquérir les réflexes C++11.