c++ optimization c++11 move-semantics return-value-optimization

c++ - ¿Mover o nombrar la optimización del valor de retorno(NRVO)?



optimization c++11 (1)

Digamos que tenemos el siguiente código:

std::vector<int> f() { std::vector<int> y; ... return y; } std::vector<int> x = ... x = f();

Parece que el compilador tiene dos enfoques aquí:

(a) NRVO: Destruye x, luego construye f () en lugar de x.
(b) Mover: construya f () en el espacio temporal, mueva f () a x, destruya f ().

¿El compilador es libre de usar cualquiera de los dos enfoques, de acuerdo con el estándar?


El compilador puede NRVO en un espacio temporal, o mover constructo a un espacio temporal. A partir de ahí se moverá asignar x .

Actualizar:

Siempre que esté tentado a optimizar con referencias de valor, y no esté seguro de los resultados, cree una clase de ejemplo que realice un seguimiento de su estado:

  • construido
  • construido por defecto
  • movido de
  • destruido

Y ejecute esa clase a través de su prueba. Por ejemplo:

#include <iostream> #include <cassert> class A { int state_; public: enum {destructed = -2, moved_from, default_constructed}; A() : state_(default_constructed) {} A(const A& a) : state_(a.state_) {} A& operator=(const A& a) {state_ = a.state_; return *this;} A(A&& a) : state_(a.state_) {a.state_ = moved_from;} A& operator=(A&& a) {state_ = a.state_; a.state_ = moved_from; return *this;} ~A() {state_ = destructed;} explicit A(int s) : state_(s) {assert(state_ > default_constructed);} friend std::ostream& operator<<(std::ostream& os, const A& a) { switch (a.state_) { case A::destructed: os << "A is destructed/n"; break; case A::moved_from: os << "A is moved from/n"; break; case A::default_constructed: os << "A is default constructed/n"; break; default: os << "A = " << a.state_ << ''/n''; break; } return os; } friend bool operator==(const A& x, const A& y) {return x.state_ == y.state_;} friend bool operator<(const A& x, const A& y) {return x.state_ < y.state_;} }; A&& f() { A y; return std::move(y); } int main() { A a = f(); std::cout << a; }

Si es útil, coloque declaraciones impresas en los miembros especiales que le interesan (por ejemplo, copie el constructor, mueva el constructor, etc.).

Por cierto, si esto te da un error, no te preocupes. Segfaults para mi tambien. Por lo tanto, este diseño en particular (devolver una referencia de valor a una variable local) no es un buen diseño. En su sistema, en lugar de segfaulting, puede imprimir "A se destruye". Esta sería otra señal de que no quieres hacer esto.