45

Il ya quelque temps, j'ai lu un article qui expliquait plusieurs pièges de la recherche dépendant d'un argument, mais je ne le trouve plus. Il s'agissait d'avoir accès à des choses auxquelles vous n'auriez pas accès ou quelque chose comme ça. Alors j'ai pensé que je demanderais ici: quels sont les pièges de l'ADL?Quels sont les pièges de l'ADL?

Répondre

63

Il y a un énorme problème avec la recherche dépendant de l'argument. Considérons, par exemple, l'utilitaire suivant:

#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); 
    } 
} 

C'est assez simple, non? Nous pouvons appeler print_n() et passer un objet et il appellera print pour imprimer l'objet n fois.

En fait, il se trouve que si on ne regarde que ce code, nous avons absolument aucune idée quelle fonction sera appelée par print_n. Il peut s'agir du modèle de fonction print donné ici, mais ce n'est peut-être pas le cas. Pourquoi? Recherche dépendante de l'argument. Par exemple, imaginons que vous ayez écrit une classe pour représenter une licorne. Par exemple, disons que vous avez écrit une classe pour représenter une licorne. Pour une raison quelconque, vous avez également défini une fonction nommée print (quelle coïncidence!) Qui provoque simplement le blocage du programme en écrivant à un pointeur nul déréférencé (qui sait pourquoi vous l'avez fait, ce n'est pas important):

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; } 
} 

Ensuite, vous écrivez un petit programme qui crée une licorne et imprime quatre fois:

int main() 
{ 
    my_stuff::unicorn x; 
    utility::print_n(x, 4); 
} 

vous compilez ce programme, exécutez, et ... il se bloque. "Quoi?", Vous dites: "Je viens d'appeler print_n, qui appelle la fonction print pour imprimer la licorne quatre fois!" Oui, c'est vrai, mais il n'a pas appelé la fonction print que vous vous attendiez à appeler. C'est ce qu'on appelle my_stuff::print.

Pourquoi my_stuff::print est sélectionné? Lors de la recherche de nom, le compilateur voit que l'argument de l'appel à print est de type unicorn, qui est un type de classe déclaré dans l'espace de noms my_stuff.

En raison de la recherche dépendant de l'argument, le compilateur inclut cet espace de noms dans sa recherche de fonctions candidates nommées print. Il trouve my_stuff::print, qui est ensuite sélectionné comme meilleur candidat viable pendant la résolution de surcharge: aucune conversion n'est requise pour appeler l'une des fonctions print candidates et les fonctions non-modèles sont préférées aux modèles de fonction, donc la fonction non-estimée my_stuff::print est la meilleure correspondance.

(Si vous ne croyez pas, vous pouvez compilez le code dans cette question comme ça, et voir ADL en action.)

Oui, la recherche dépendante argument est une caractéristique importante de C++. Il est essentiellement nécessaire d'atteindre le comportement souhaité de certaines fonctionnalités de langage comme les opérateurs surchargés (considérez la bibliothèque de flux). Cela dit, c'est aussi très, très imparfait et peut conduire à des problèmes vraiment laids. Il y a eu plusieurs propositions pour corriger la recherche dépendant des arguments, mais aucune d'entre elles n'a été acceptée par le comité des normes C++.

+0

Je devrais probablement noter que cet exemple a été inspiré par une présentation sur le sujet que Bartosz Milewski a donné; Je n'ai pas les diapositives de cette présentation, et ce n'est pas exactement la même chose, mais c'est proche. –

+6

Est-ce un piège des AVQ ou un piège de ne pas utiliser ADL soigneusement? – Chubsdad

+13

@ Chubsdad: C'est un énorme piège de l'ADL. Le problème est que vous pouvez écrire deux bibliothèques qui sont totalement indépendantes et accidentellement confrontées à ce problème sans avoir aucune idée que vous allez avoir des problèmes. Aucune "prudence" ne peut vous protéger complètement de cela. –

Questions connexes