que punteros puntero apuntadores c++ namespaces swap using-directives argument-dependent-lookup

c++ - apuntadores - ¿Por qué swap() puede funcionar bien cuando no lo llamo con dos punteros?



que es el puntero del mouse (5)

#include <iostream> using namespace std; void swap(int *a, int *b) { *a = *a^*b; *b = *a^*b; *a = *a^*b; } int main() { int array[]={1,9,2,8,3,7}; for(int i=0; i<6; i++) cout<<array[i]; cout<<endl; swap(array[1], array[4]); for(int i=0; i<6;i++) cout<<array[i]; cout<<endl; return 0; }

arriba hay una muestra de prueba. Me parece que si uso swap(array[1], array[4]); , también intercambia los valores de dos posiciones en el conjunto. Pero esto me confunde, porque la función swap() necesita dos punteros, no dos valores enteros.

Gracias por tu ayuda:)


Es por eso que debe evitar el using namespace std; .

La inclusión de un encabezado estándar aparentemente ha arrastrado una declaración de std::swap en su programa; y using namespace std; lo ha vertido en el espacio de nombres global. Entonces su código llama eso, no su versión.


No usa su swap , pero std::swap .

Intente llamarlo como ::swap(array[1], array[4]); y obtendrás un error.

Es por eso que using namespace std; es malo.


using namespace std;

Este es tu culpable. Cuando importa el std:: nombres std:: , obtiene todos los identificadores declarados en ese espacio de nombres, lo que potencialmente incluye std::swap .

Por lo tanto, está invocando std::swap<int>(int&,int&) (desde la biblioteca estándar) y no ::swap(int*,int*) (desde su programa).

La moraleja de la historia: nunca digas using namespace std; . Es demasiado grande.


Su problema no tiene nada que ver con el using namespace std; . El problema es que está pasando una referencia lvalue a un int ( int& ) a una función que está sobrecargada en int& y int* . Si eliminaste la directiva using, no estarías llamando a tu propio swap; de hecho, su código no compilaría, ya que C ++ no permite la conversión implícita de punteros a int. Para usar su función, debería llamarla como swap(&array[1], &array[4]);

Ahora, si corrigió su llamada de función para reflejar esto, debería funcionar, independientemente de la presencia de la directiva using. Sin embargo, recomendaría no hacerlo; la semántica de std::swap consiste en intercambiar dos referencias , no punteros. No solo está sobrecargando las funciones estándar con una semántica incompatible que confunde a los que están familiarizados con la biblioteca estándar, también puede romper el código perfectamente válido que usa std::swap en int* .

Usted puede estar pensando: "Pero eso solo ocurrirá si using namespace std; , lo que nunca deberían hacer". Créalo o no, sin embargo, el swap es exactamente el tipo de aplicación en la que desea que se use la directiva (con un ámbito adecuado, por supuesto). La razón para esto es que el código de usuario puede hacer exactamente lo que está tratando de hacer: especializar el algoritmo de swap . Si algún código de biblioteca simplemente dijera std::swap , cualquier sobrecarga definida por el usuario sería ignorada, haciendo que esa sobrecarga sea inútil. Si, en cambio, su código se viera como

template <typename T> void foo (T& a, T& b) { using std::swap; // Or simply namespace std; // ... swap (a, b); // ... }

el compilador podría emplear ADL correctamente y elegir swap definido por el usuario para cualquier T dado (por ejemplo, int ), mientras que todavía puede usar std::swap para otros T.

En otras palabras: siempre proporcione parámetros de referencia de swap , y use una declaración de uso de ámbito cada vez que necesite cambiar los tipos de plantilla.


¿Ofrecerías otra respuesta para resolver este problema sin una variable temporal?

No creo que se pueda hacer. De todos modos, ¿de dónde viene el requisito "sin variable temporal"? ¿Crees que las variables temporales hacen que tu código sea más lento? Examinemos si este es el caso aquí.

Anexo A: Algunos pirateo. No es inmediatamente obvio cómo funciona. No se puede intercambiar una variable consigo mismo correctamente:

void swap1(int* a, int* b) { *a = *a ^ *b; *b = *a ^ *b; *a = *a ^ *b; }

Código de ensamblaje generado:

movl (%rsi), %eax xorl (%rdi), %eax movl %eax, (%rdi) xorl (%rsi), %eax movl %eax, (%rsi) xorl %eax, (%rdi)

Anexo B: código directo con una variable temporal. Puede intercambiar una variable consigo mismo correctamente:

void swap2(int* a, int* b) { int c = *a; *a = *b; *b = c; }

Código de ensamblaje generado:

movl (%rdi), %eax movl (%rsi), %edx movl %edx, (%rdi) movl %eax, (%rsi)

La solución de variables temporales es más fácil de entender, maneja todos los casos y resultados en un código más rápido.

Una vez más, fuera de las situaciones de entrevista, el truco xor es completamente inútil. Y si yo fuera el entrevistador y el candidato conociera el truco xor pero no lo calificara diciendo "Este es un truco lindo, pero nunca usaría esto en el mundo real", estoy seguro de que no lo contrataría. Déjame terminar esta respuesta con una cita:

La claridad supera a la astucia todo el tiempo. Larry Osterman