Hace algún tiempo, leí un artículo que explicaba varias trampas de la búsqueda dependiente de argumentos, pero no puedo encontrarlo más. Se trataba de obtener acceso a cosas a las que no deberías acceder o algo así. Así que pensé en preguntar aquí: ¿cuáles son los peligros de ADL?¿Cuáles son los peligros de ADL?
Respuesta
Hay un gran problema con la búsqueda dependiente de argumentos. Considere, por ejemplo, la siguiente utilidad:
#include <iostream>
namespace utility
{
template <typename T>
void print(T x)
{
std::cout << x << std::endl;
}
template <typename T>
void print_n(T x, unsigned n)
{
for (unsigned i = 0; i < n; ++i)
print(x);
}
}
Es lo suficientemente simple, ¿no? Podemos llamar al print_n()
y pasarle cualquier objeto y llamará al print
para imprimir el objeto n
veces.
En realidad, resulta que si solo miramos este código, tenemos absolutamente ninguna idea qué función será llamada por print_n
. Puede ser la plantilla de función print
que se proporciona aquí, pero puede que no sea así. ¿Por qué? Búsqueda dependiente de argumentos.
Como ejemplo, digamos que ha escrito una clase para representar a un unicornio. Por alguna razón, también ha definido una función llamada print
(¡qué coincidencia!) Que causa que el programa se cuelgue al escribir en un puntero nulo sin referencias (quién sabe por qué lo hizo; eso no es importante):
namespace my_stuff
{
struct unicorn { /* unicorn stuff goes here */ };
std::ostream& operator<<(std::ostream& os, unicorn x) { return os; }
// Don't ever call this! It just crashes! I don't know why I wrote it!
void print(unicorn) { *(int*)0 = 42; }
}
a continuación, escribir un pequeño programa que crea un unicornio y lo imprime en cuatro ocasiones:
int main()
{
my_stuff::unicorn x;
utility::print_n(x, 4);
}
compilar este programa, ejecuta, y ... se bloquea. "¡De ninguna manera!", Dices: "¡Acabo de llamar al print_n
, que llama a la función print
para imprimir el unicornio cuatro veces!" Sí, eso es cierto, pero no ha llamado a la función print
que esperaba que llamara. Se llama my_stuff::print
.
¿Por qué se selecciona my_stuff::print
? Durante la búsqueda de nombres, el compilador ve que el argumento de la llamada a print
es del tipo unicorn
, que es un tipo de clase que se declara en el espacio de nombres my_stuff
.
Debido a la búsqueda dependiente del argumento, el compilador incluye este espacio de nombres en su búsqueda de funciones candidatas llamadas print
. Encuentra my_stuff::print
, que luego se selecciona como el mejor candidato viable durante la resolución de sobrecarga: no se requiere conversión para llamar a cualquiera de las funciones candidatas print
y las funciones no de plantilla son preferibles a las plantillas de función, por lo que la función no de plantilla my_stuff::print
es la mejor coincidencia.
(Si usted no cree esto, se puede compilar el código en esta pregunta como está y ve ADL en acción.)
Sí, las operaciones de búsqueda argumento-dependiente es una característica importante de C++. Esencialmente se requiere para lograr el comportamiento deseado de algunas características del lenguaje, como los operadores sobrecargados (considere la biblioteca de secuencias). Dicho esto, también es muy, muy defectuoso y puede conducir a problemas realmente desagradables. Ha habido varias propuestas para corregir búsquedas dependientes de argumentos, pero ninguna de ellas ha sido aceptada por el comité de estándares de C++.
- 1. ¿Cuáles son los peligros de usar sql_variant?
- 2. ¿Cuáles son los peligros de la prueba después del desarrollo?
- 3. ¿Cuáles son los peligros de ejecutar jQuery sin $ (document) .ready() ;?
- 4. ¿Cuáles son los peligros de un idioma que es "propiedad"?
- 5. ¿Cómo funcionan los subprocesos en Python, y cuáles son los peligros específicos de Python-threading?
- 6. ¿Cuáles son los beneficios y los peligros de agregar métodos a Object.prototype en Javascript?
- 7. ¿Cuáles son los peligros de utilizar un Singleton en una aplicación de subprocesos múltiples
- 8. ¿Cuáles son los peligros de hacer que un método sea virtual?
- 9. ¿Cuáles son los peligros de una conexión integrada a Derby en una red?
- 10. ¿Cuáles son los peligros de utilizar OpenID para su sitio web?
- 11. ¿Cuáles son los peligros de utilizar .NET RIA Services en Silverlight?
- 12. ¿Cuáles son los nuevos marcos?
- 13. la comprensión de los peligros de sprintf (...)
- 14. ¿Cuáles son los inconvenientes de configurar enable_nestloop en OFF
- 15. ¿Cuáles son los usos de buffer circular?
- 16. ¿Cuáles son los usos de svn copy?
- 17. ¿Cuáles son los beneficios de letrec?
- 18. ¿Cuáles son los méritos relativos de pdflatex?
- 19. ¿Cuáles son los otros valores de NaN?
- 20. ¿Cuáles son los mejores componentes de Boost?
- 21. ¿Cuáles son los beneficios de Persistence Ignorance?
- 22. ¿Cuáles son los repositorios predeterminados de leiningen?
- 23. ¿Cuáles son los beneficios de JCA?
- 24. ¿Cuáles son los comandos importantes de Ruby?
- 25. ¿Cuáles son los inconvenientes de usar Lucene?
- 26. ¿Cuáles son los usos comunes de UDP?
- 27. ¿Cuáles son los beneficios de Java?
- 28. ¿Cuáles son los mayores beneficios de LLVM?
- 29. ¿Cuáles son los usos de Cross Join?
- 30. ¿Cuáles son los beneficios de JRebel?
Probablemente debería tener en cuenta que este ejemplo fue inspirado por una presentación sobre el tema que dio Bartosz Milewski; No tengo las diapositivas de esa presentación, y no es exactamente lo mismo, pero está cerca. –
¿Es esto un escollo de ADL o la trampa de no usar ADL con cuidado? – Chubsdad
@Chubsdad: es una gran trampa de ADL. El problema es que puede escribir dos bibliotecas que son totalmente independientes y se topan accidentalmente con este problema sin tener idea de que va a haber problemas. Ninguna cantidad de "cuidado" puede protegerlo completamente de esto. –