what - reference function c++
¿Cuándo es una referencia de const mejor que pass-by-value en C++ 11? (5)
La semántica de movimiento de C ++ 11 hace que pasar y regresar por valor sea mucho más atractivo incluso para objetos complejos.
La muestra que proporcionas, sin embargo, es una muestra de pase por valor
int hd(vector<int> a) {
Entonces C ++ 11 no tiene ningún impacto en esto.
Incluso si hubiera declarado correctamente ''hd'' para tomar un valor r
int hd(vector<int>&& a) {
puede ser más barato que pasar por valor, pero realizar un movimiento exitoso (a diferencia de un simple std::move
que puede no tener ningún efecto) puede ser más costoso que un simple pase de referencia. Se debe construir un nuevo vector<int>
y debe tomar posesión de los contenidos de a
. No tenemos la sobrecarga antigua de tener que asignar una nueva matriz de elementos y copiar los valores, pero aún tenemos que transferir los campos de datos de vector
.
Más importante aún, en el caso de una mudanza exitosa, a
se destruiría en este proceso:
std::vector<int> x;
x.push(1);
int n = hd(std::move(x));
std::cout << x.size() << ''/n''; // not what it used to be
Considere el siguiente ejemplo completo:
struct Str {
char* m_ptr;
Str() : m_ptr(nullptr) {}
Str(const char* ptr) : m_ptr(strdup(ptr)) {}
Str(const Str& rhs) : m_ptr(strdup(rhs.m_ptr)) {}
Str(Str&& rhs) {
if (&rhs != this) {
m_ptr = rhs.m_ptr;
rhs.m_ptr = nullptr;
}
}
~Str() {
if (m_ptr) {
printf("dtor: freeing %p/n", m_ptr)
free(m_ptr);
m_ptr = nullptr;
}
}
};
void hd(Str&& str) {
printf("str.m_ptr = %p/n", str.m_ptr);
}
int main() {
Str a("hello world"); // duplicates ''hello world''.
Str b(a); // creates another copy
hd(std::move(b)); // transfers authority for b to function hd.
//hd(b); // compile error
printf("after hd, b.m_ptr = %p/n", b.m_ptr); // it''s been moved.
}
Como regla general:
- Pase por valor para objetos triviales,
- Pase por valor si el destino necesita una copia mutable,
- Pase por valor si siempre necesita hacer una copia,
- Pase por la referencia constante para objetos no triviales donde el espectador solo necesita ver el contenido / estado pero no necesita que sea modificable,
- Mover cuando el destino necesita una copia mutable de un valor temporal / construido (por ejemplo,
std::move(std::string("a") + std::string("b")))
. - Se mueve cuando necesita localidad del estado del objeto pero desea retener los valores / datos existentes y liberar el titular actual.
Tengo un código pre-C ++ 11 en el que utilizo las referencias const
para pasar parámetros grandes como vector
''sa lot. Un ejemplo es el siguiente:
int hd(const vector<int>& a) {
return a[0];
}
Escuché que con las nuevas características de C ++ 11, puede pasar el vector
por valor de la siguiente manera sin hits de rendimiento.
int hd(vector<int> a) {
return a[0];
}
Por ejemplo, esta respuesta dice
La semántica de movimiento de C ++ 11 hace que pasar y regresar por valor sea mucho más atractivo incluso para objetos complejos.
¿Es cierto que las dos opciones anteriores son las mismas en cuanto a rendimiento?
Si es así, ¿cuándo se usa la referencia constante como en la opción 1 mejor que la opción 2? (es decir, ¿por qué todavía necesitamos usar las referencias de const en C ++ 11).
Una de las razones por las que pregunto es que las referencias de referencias complican la deducción de los parámetros de la plantilla, y sería mucho más fácil usar solo el valor de paso por paso, si es lo mismo con la referencia de referencia de rendimiento.
Existe una gran diferencia. Obtendrás una copia de la matriz interna de un vector
menos que esté a punto de morir.
int hd(vector<int> a) {
//...
}
hd(func_returning_vector()); // internal array is "stolen" (move constructor is called)
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
hd(v); // internal array is copied (copy constructor is called)
C ++ 11 y la introducción de referencias rvalue cambiaron las reglas sobre el retorno de objetos como vectores; ahora puede hacerlo (sin preocuparse por una copia garantizada). Sin embargo, no cambiaron las reglas básicas sobre tomarlos como argumento; aún así debes tomarlos por referencias, a menos que realmente necesites una copia real, por valor entonces.
La regla general para pasar por valor es cuando terminarías haciendo una copia de todos modos. Es decir que en lugar de hacer esto:
void f(const std::vector<int>& x) {
std::vector<int> y(x);
// stuff
}
donde primero pasas un const-ref y luego lo copias, deberías hacer esto en su lugar:
void f(std::vector<int> x) {
// work with x instead
}
Esto ha sido parcialmente cierto en C ++ 03 y se ha vuelto más útil con la semántica de movimiento, ya que la copia puede ser reemplazada por un movimiento en el caso de paso por val cuando la función se llama con un valor r.
De lo contrario, cuando todo lo que desea hacer es leer los datos, pasar por referencia const
sigue siendo la forma preferida y eficiente.
Recuerde que si no está pasando un valor r, entonces pasar por valor resultaría en una copia completa. Por lo tanto, hablando en términos generales, pasar de valor puede generar un golpe de rendimiento.
Tu ejemplo es defectuoso. C ++ 11 no te da un movimiento con el código que tienes, y se haría una copia.
Sin embargo, puede obtener un movimiento declarando que la función toma una referencia de valor real y luego pasa una:
int hd(vector<int>&& a) {
return a[0];
}
// ...
std::vector<int> a = ...
int x = hd(std::move(a));
Eso supone que no usará la variable a
en su función nuevamente, excepto para destruirla o asignarle un nuevo valor. Aquí, std::move
arroja el valor a una referencia rvalue, permitiendo el movimiento.
Las referencias de Const permiten que los temporales se creen silenciosamente. Puede pasar algo que sea apropiado para un constructor implícito, y se creará un temporal. El ejemplo clásico es una matriz char que se convierte en const std::string&
pero con std::vector
, se puede convertir una std::initializer_list
.
Asi que:
int hd(const std::vector<int>&); // Declaration of const reference function
int x = hd({1,2,3,4});
Y, por supuesto, también puedes mover el temporal:
int hd(std::vector<int>&&); // Declaration of rvalue reference function
int x = hd({1,2,3,4});