45

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

63

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++.

+0

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. –

+6

¿Es esto un escollo de ADL o la trampa de no usar ADL con cuidado? – Chubsdad

+13

@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. –

Cuestiones relacionadas