Czy elision / przyporządkowanie domyślnego konstruktora jest możliwe w zasadzie?
. lub nawet dozwolone przez standard C ++ 11?
A jeśli tak, to czy istnieje jakiś kompilator, który rzeczywiście to robi?
Oto przykład tego, co mam na myśli:
template<class T> //T is a builtin type
class data
{
public:
constexpr
data() noexcept :
x_{0,0,0,0}
{}
constexpr
data(const T& a, const T& b, const T& c, const T& d) noexcept :
x_{a,b,c,d}
{}
data(const data&) noexcept = default;
data& operator = (const data&) noexcept = default;
constexpr const T&
operator[] (std::size_t i) const noexcept {
return x_[i];
}
T&
operator[] (std::size_t i) noexcept {
return x_[i];
}
private:
T x_[4];
};
template<class Ostream, class T>
Ostream& operator << (Ostream& os, const data<T>& d)
{
return (os << d[0] <<' '<< d[1] <<' '<< d[2] <<' '<< d[3]);
}
template<class T>
inline constexpr
data<T>
get_data(const T& x, const T& y)
{
return data<T>{x + y, x * y, x*x, y*y};
}
int main()
{
double x, y;
std::cin >> x >> y;
auto d = data<double>{x, y, 2*x, 2*y};
std::cout << d << std::endl;
//THE QUESTION IS ABOUT THIS LINE
d = get_data(x,y);
d[0] += d[2];
d[1] += d[3];
d[2] *= d[3];
std::cout << d << std::endl;
return 0;
}
Odnośnie zaznaczonej linii:
Czy wartości x + y, x * y, x * x, y * y można zapisać bezpośrednio w pamięci d? Czy może zwracać typ get_data bezpośrednio w pamięci d?
Nie mogę wymyślić powodu, aby nie pozwolić na taką optymalizację. Przynajmniej nie dla klasy, która ma tylko konstruktory constexpr i domyślne operatory kopiowania i przypisania.
g ++ 4.7.2 usuwa wszystkie konstruktory kopii w tym przykładzie; wydaje się jednak, że przypisanie jest zawsze wykonywane (nawet tylko w przypadku domyślnego przypisania - o ile wiem z zespołu, który emituje g ++).
Motywacją dla mojego pytania jest następująca sytuacja, w której taka optymalizacja znacznie uprościłaby i poprawiła projektowanie biblioteki. Załóżmy, że piszesz procedury biblioteczne o krytycznym znaczeniu dla wydajności, używając klasy literalnej. Obiekty tej klasy będą posiadać wystarczającą ilość danych (powiedzmy 20 podwójnych), że kopie muszą być ograniczone do minimum.
class Literal{ constexpr Literal(...): {...} {} ...};
//nice: allows RVO and is guaranteed to not have any side effects
constexpr Literal get_random_literal(RandomEngine&) {return Literal{....}; }
//not favorable in my opinion: possible non-obvious side-effects, code duplication
//would be superfluous if said optimization were performed
void set_literal_random(RandomEngine&, Literal&) {...}
Pozwoliłoby to na znacznie czystszy (styl programowania funkcjonalnego) projekt, gdybym mógł zrezygnować z drugiej funkcji. Ale czasami muszę tylko zmodyfikować długotrwały obiekt dosłowny i upewnić się, że nie utworzę nowego obiektu i skopiować go do tego, który chcę zmodyfikować. Sama modyfikacja jest tania, kopie nie - tak wskazują moje eksperymenty.
EDYTOWAĆ:
Załóżmy, że optymalizacja będzie dozwolona tylko dla klasy z konstruktorami constexpr noexcept i operatorem domyślnym noexcept =.