pointer functions examples c++ function pointers

functions - Funciones de C++: ampersand vs asterisk



pointers to functions in c++ examples (9)

El primero te obliga a llamar a la función con myfunc (& b) para que la persona que llama sepa que b se modificará

a veces la función podría aceptar el puntero const y el que llama tendrá el pensamiento erróneo de que b será modificado.

Mi recomendación: prefiera usar referencias donde sea posible (por supuesto, donde sea necesario). En caso de argumento de función, obtenemos beneficios:
- las referencias no pueden ser NULL - nos ayudan a evitar errores y afirmaciones o verificaciones innecesarias.
- las referencias tienen solo un punto de inicialización y en la función boody siempre se sabe en qué cosa apunta el parámetro de entrada.

Soy mantenedor en proyecto grande. Y en cualquier caso, estoy buscando la definición de la función antes de invocarla. Por supuesto, cuando busco la definición de función veo la definición de argumentos por valor, por referencia, por referencia constante o por puntero.

Pero parece una cuestión de guerra santa, los pueblos diferentes tienen una visión diferente sobre este punto. Por ejemplo, la recomendación de uso de la codificación de Google recomienda usar punteros en los argumentos que podrían modificarse y permitir solo las referencias const: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

Todos los parámetros pasados ​​por referencia deben etiquetarse const.

Digamos que tienes una función que modifica una variable.

¿Debería escribirlo así: void myfunc(int *a) o como este void myfunc(int &a) ?

El primero te obliga a llamar a la función con myfunc(&b) para que la persona que llama sepa que b se modificará, pero esta última es más corta y se puede llamar simplemente con myfunc(b) . Entonces, ¿cuál es mejor usar? ¿Hay algo más que me estoy perdiendo?


Algo a tener en cuenta, si está utilizando funtores stl, es más fácil si el parámetro coincide con el tipo de valor del contenedor.

void foo(Bar *); void frobnicate(vector<Bar *> vecBars) { for_each(vecBars.begin(), vecBars.end(), ptr_fun(&foo)); }

El código anterior es mucho más difícil si foo toma Bar &


Baje por el lado del puntero de la valla, por las razones citadas aquí y en todas partes. Sin embargo, le diré que sea lo que sea que decida, debe ser coherente y documentarlo en su guía de estilo.

La guía de estilo de Google C ++ bans los argumentos de referencia no const.


Creo que no estaría de acuerdo con @bb y @JaredPar y me inclino hacia el lado opuesto de la valla. Después de años de intentar apoyar el código C ++ de otras personas, a menudo encuentro problemas al acecho en los efectos secundarios no obvios de los argumentos de referencia. Con C #, es obvio ya que tiene que prefijar tipos de argumentos con ''ref'' / ''out'', pero las referencias son potencialmente confusas en C ++. Entonces, me gustan los indicadores porque es muy claro que algo está volviendo. Si no te gustan los puntos, C ++ no es para ti.


En un mundo ideal, se trata de si el parámetro es o no una salida opcional. ¿Quieres permitir que la persona que llama pase NULL si no les importa? Luego usa un puntero. De lo contrario, una referencia es una mejor opción.

Tenga en cuenta que, en ambos casos, el lenguaje hace que sea engorroso documentar un parámetro de salida. Es mucho mejor si toda la base de código es const correcta, entonces los usuarios pueden suponer que cualquier referencia no const o parámetro de puntero es una salida.


Los punteros (es decir, el ''*'') se deben usar cuando el paso "NULL" sea significativo. Por ejemplo, puede usar un NULO para representar que un objeto en particular necesita ser creado, o que una acción en particular no necesita ser tomada. O si alguna vez necesita ser llamado desde un código que no sea C ++. (por ejemplo, para uso en bibliotecas compartidas)

p.ej. La función libc time_t time (time_t *result);

Si el result no es NULO, se almacenará la hora actual. Pero si el result es NULL, entonces no se realiza ninguna acción.

Si la función que está escribiendo no necesita usar NULL como un valor significativo, entonces el uso de referencias (es decir, el ''&'') probablemente sea menos confuso, suponiendo que esa sea la convención que usa su proyecto.


Me gusta pasar por referencia si NULL no tiene significado, pero puedo ver los argumentos para ambos. Si tiene cuidado con la codificación, probablemente pueda eliminar la objeción accidental de pasar por referencia asegurándose de pasar siempre las variables por referencia constante, por ejemplo:

myfunc( const_cast< const int& >( a ) ); // Alternatively, this approach may require additional handling // in the function, but it''s cleaner at call point myfunc( boost::cref( a ) );

Sin embargo, eso es mucho código adicional para poco beneficio. Como señaló Kenny, C # trató esto desde el extremo opuesto (requiriendo paso específico por referencia), pero esa no es una opción para C ++ (a menos que, por ejemplo, escribas tus funciones para tomar un contenedor de referencia como su parámetro, como boost :: ref (param)), por ejemplo:

void myfunc( const boost::reference_wrapper< int >& a ) { ... }

Sin embargo, solucionar el problema del puntero es más problemático ... no hay forma de tiempo de compilación para garantizar que el puntero sea válido, por lo que se terminan con problemas de tiempo de ejecución para problemas con el puntero o controles de tiempo de ejecución, o ambos. Esta es la naturaleza de los indicadores.

De todos modos, esa es solo mi opinión, por lo que vale.


Siempre que sea posible, uso referencias sobre punteros. La razón de esto es que es mucho más difícil arruinar una referencia que un puntero. Las personas siempre pueden pasar NULL a un valor de puntero, pero no hay tal equivalente a una referencia.

El único inconveniente real es que los parámetros de referencia en C ++ carecen de documentación del sitio de llamada. Algunas personas creen que eso hace que sea más difícil entender el código (y estoy de acuerdo en cierta medida). Por lo general, defino lo siguiente en mi código y lo uso para la documentación falsa del sitio de llamadas

#define byref ... someFunc(byref x);

Esto, por supuesto, no hace cumplir la documentación del sitio de llamada. Simplemente proporciona una manera muy pobre de documentarlo. Hice algo de experimentación con una plantilla que impone la documentación del sitio de llamada. Sin embargo, esto es más por diversión que por código de producción real.

http://blogs.msdn.com/jaredpar/archive/2008/04/03/reference-values-in-c.aspx


Una diferencia, como se ha mencionado anteriormente, es que no puede pasar una referencia nula, pero puede pasar un puntero nulo.

Otra cosa, también mencionada anteriormente, cuando llamas a f(a,b) podría haber confusión si la persona que llama no sabe que f podría cambiar el valor de b

Sin embargo, otro problema, que es bastante sutil, pero todavía me encontré con él , es la semántica de las referencias.

Los punteros se pasan por valor, pero las referencias no lo son.

Lo que significa que si pasa un parámetro por un puntero, puede cambiar el puntero y hacer que apunte a otra cosa.

Considera esto:

void f1_ptr( type * a ) { a = new type(); //no change to passed parameters, you''re changing the pointer which was passed by value } void f2_ptr( type * a ) { *a = some_other_value; //now you''re changing the value of the parameter that was passed //or, if type is a class or struct: a->some_method_that_modifies_object(); //again, changing the parameter that was passed }

Pero, al pasar por referencia, no puede cambiar la referencia para referirse a otro valor. Una vez que se establece la referencia, no se puede cambiar.

void f3_ref( type& a ) { a = type(); //the referred variable has also changed } //.... type obj = type( params ); f3_ref( obj ); //obj now changed f1_ptr( &obj ); //obj doesn''t change f2_ptr( &obj ); //obj now changed