c++ - sirve - Devuelve valores de copia de declaración
void c++ (10)
Devuelve una copia, que es lo que quieres que haga. Cambiarlo para devolver una referencia dará como resultado un comportamiento indefinido en la asignación a la línea.
Sin embargo, la forma idiomática de hacer esto en C ++ es con constructores y listas de asignación. Esto encapsula mejor el código y las estructuras de datos, y le permite evitar la gran cantidad de objetos intermedios que los compiladores son libres de construir / destruir / copiar.
struct subline_t {
int x1;/*top*/
int x2;/*bottom*/
int id;
// constructor which initialises values with assignment list.
subline_t(int the_x1, int the_x2, int the_id) :
x1(the_x1),
x2(the_x2),
id(the_id)
{
}
};
int main(){
subline_t line2(0,0,0); // never requires a copy or assignment.
}
Me pregunto sobre esto debido a problemas de alcance. Por ejemplo, considere el código
typedef struct {
int x1;/*top*/
int x2;/*bottom*/
int id;
} subline_t;
subline_t subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t;
}
int main(){
subline_t line = subline(0,0,0); //is line garbage or isn''t it? the reference
//to subline_t t goes out of scope, so the only way this wouldn''t be garbage
//is if return copies
}
Entonces mi pregunta es, ¿la declaración de devolución siempre copiará? En este caso parece funcionar, así que me hacen creer que el retorno sí lo hace. Si lo hace, ¿se copiará en todos los casos?
En su caso, devolverá una copia
Si tu código era
subline_t& subline(int, int)
entonces devolvería una referencia, que cedería en un comportamiento indefinido.
La clase o estructura devuelta puede o no copiarse, dependiendo de si el compilador usa elisión de copia. Vea las respuestas a ¿Qué son elisión de copia y optimización del valor de retorno? En resumen, si se copia o no depende de varias cosas.
Por supuesto, puede evitar una copia devolviendo una referencia. En el caso de su ejemplo, devolver una referencia no es válido (aunque el compilador lo permitirá) porque la estructura local está asignada en la pila y, por lo tanto, la referencia devuelta hace referencia a un objeto desasignado. Sin embargo, si el objeto se transfirió a su función (directamente o como miembro de un objeto) puede devolver una referencia de manera segura y evitar la copia en el retorno.
Finalmente, si no puede confiar en la elisión de copia y desea evitar copias, puede usar y devolver un unique_ptr
lugar de una referencia. El objeto en sí no se copiará, aunque el unique_ptr
sí mismo puede ser o no (de nuevo, ¡dependiendo de elisión de copia!). Copiar / mover un unique_ptr
es, sin embargo, muy barato si la elisión de copia del unique_ptr
no ocurre por alguna razón.
Aquí hay un ejemplo usando unique_ptr
:
#include <memory>
struct A {
public:
int x;
int y;
A(int x, int y) : x(x), y(y) {
}
};
std::unique_ptr<A> returnsA() {
return std::make_unique<A>(3, 4);
}
int main() {
auto a = returnsA();
}
Tenga en cuenta que debe (desafortunadamente) declarar un constructor para su estructura, o bien make_unique
no se compilará debido a las deficiencias de C ++.
Para la estructura subline_t
que ha definido, sí, siempre devolverá una copia.
Returing objetos en C ++ hechos por valor y no por referencia.
la referencia a subline_t t sale del alcance
No, el objeto está copiado.
la declaración de devolución siempre copia
Sí y no ... Semánticamente se comporta como copiar, pero hay algo que se llama optimización de valor de retorno que salva el constructor de copias.
foo make_foo()
{
foo f(1,2,3);
return f;
}
foo ff=make_foo(); /// ff created as if it was created with ff(1,2,3) -- RVO
foo ff2;
ff2=make_foo(); /// instance of foo created and then copied to ff2 and then old
/// instance destroyed
Sí, en ese caso habrá una copia. Si cambia la declaración de función de esta manera:
subline_t &subline(int x1, int x2, int id) {
entonces no se hará ninguna copia. Sin embargo, en su caso específico, no sería válido devolver una referencia a un objeto asignado en la pila. El problema es que el objeto sería destruido e invalidado antes de que la persona que llama tuviera la oportunidad de usarlo.
Esto está relacionado con la Optimización del valor de retorno común para C ++ que puede evitar hacer una operación de copia real en el caso que ha descrito. El resultado final es (o debería ser) el mismo que si se realizara una copia, pero debe tener en cuenta la optimización. La presencia de esta optimización puede, en algunos casos, cambiar el comportamiento observable del programa.
Sí, para una función declarada para devolver una struct
, el return
de dicha estructura la copiará (aunque el compilador tiene la facultad de optimizar la copia, esencialmente en los casos en que puede demostrar que la optimización es semánticamente inocua, puede razonar "como si "la copia estaba garantizada).
Sin embargo, como etiquetaste esto como C ++, no como C, ¿por qué no proporcionar tu struct
con un constructor, en cambio ...? ¡Parece más claro y más directo ...! -)
Siempre devolverá una copia.
Si desea evitar el golpe de rendimiento al copiar el objeto en el retorno, puede declarar un puntero, crear una instancia del objeto utilizando new y devolver el puntero. En ese caso, el puntero se copiará, pero el objeto no será.
Solo para tu información, ya que en este caso estás usando solo una estructura (ure), es el mismo comportamiento que en el lenguaje C.
Aunque esta es una función de idioma, se recomienda que no se use
sí, la devolución es una copia
subline_t subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t;
}
Si pones un referenciador, entonces no es una copia
subline_t & subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t; // will result in corruption because returning a reference
}