27 votes

Pourquoi les pointeurs de fonctions (membres) se comportent-ils si étrangement dans Visual C ++?

J'ai eu un problème vraiment bizarre que j'ai réduit au cas de test suivant:

 #include <iostream>
#include <map>
#include <string>

struct Test
{
    std::map<std::string, void (Test::*)()> m;
    Test()
    {
        this->m["test1"] = &Test::test1;
        this->m["test2"] = &Test::test2;
    }
    void test1() { }
    void test2() { }
    void dispatch(std::string s)
    {
        if (this->m.at(s) == &Test::test1)
        { std::cout << "test1 will be called..." << std::endl; }
        else if (this->m.at(s) == &Test::test2)
        { std::cout << "test2 will be called..." << std::endl; }
        (this->*this->m.at(s))();
    }
};

int main()
{
    Test t;
    t.dispatch("test1");
    t.dispatch("test2");
}
 

Il produit

test1 sera appelé ...
test1 sera appelé ...

lorsque les optimisations sont activées, ce qui est vraiment bizarre. Que se passe-t-il?

27voto

jstine Points 2062

C'est un sous-produit de ce que Visual C++ désigne comme Pliage de COMDAT Identique (ICF). Elle associe des fonctions identiques en une seule instance. Vous pouvez la désactiver en ajoutant le commutateur suivant l'éditeur de liens en ligne de commande: /OPT:NOICF (à partir de l'INTERFACE utilisateur de Visual Studio, il est constaté en vertu de Propriétés->Linker->Optimisation->Activer le Pliage de COMDAT)

Vous pouvez trouver plus de détails à l'article MSDN ici: /OPT (Optimisations)

Le commutateur est un éditeur de liens-stade de l'interrupteur, ce qui signifie que vous ne serez pas en mesure de l'activer juste pour un module spécifique ou une région spécifique de code (comme __pragma( optimize() ) qui est disponible pour le compilateur étape d'optimisation).

En général, cependant, il est considéré comme une mauvaise pratique de s'appuyer sur des pointeurs de fonction ou de littéraux de chaîne de pointeurs (const char*) pour les tests de l'unicité. Chaîne de pliage est largement mis en œuvre par presque tous les compilateurs C/C++. La fonction de pliage n'est disponible que sur Visual C++ en ce moment, mais une hausse de l'utilisation généralisée de template<> méta-programmation a une augmentation des demandes pour que cette fonctionnalité soit ajoutée à gcc et clang toolchains.

Edit: en Commençant par binutils 2.19, inclus l'or de l'éditeur de liens soi-disant prend également en charge l'ICF, même si j'ai pas été en mesure de vérifier sur mon local Ubuntu 12.10 installer.

17voto

Mehrdad Points 70493

Il s'avère que l'éditeur de liens de Visual C ++ peut fusionner des fonctions avec des définitions identiques en une seule.
Que ce soit légal ou non selon C ++, je n'en ai aucune idée; cela affecte le comportement observable, donc cela ressemble à un bug pour moi. Cependant, quelqu'un d'autre avec plus d'informations voudra peut-être y répondre.

6voto

C++11 5.3.1 décrit ce qu' & t; dans ce cas, il vous donne un pointeur vers la fonction de membre en question, et le passage ne comporte aucune exigence en ce pointeur doit être unique.

Cependant, 5.10/1 dit à propos de l' ==:

Deux pointeurs du même type de comparer l'égalité si et seulement si ils sont tous deux nuls, deux points de la même fonction, ou les deux représentent la même adresse.

La question devient alors... êtes - test1 et test2 "la même fonction"?

Si l'optimiseur s'est effondré en une seule définition, sans doute les deux noms d'identifier deux fonctions et, en tant que tel, cela semble être un bug de mise en œuvre.

(Notez, cependant, que le VS team n'avez pas de soins et les considèrent comme "valables" pour justifier les avantages de l'optimisation. Que, ou ils ne savent pas que c'est non valide.)

Je collerais à l'aide de cordes comme des "poignées" pour votre pointeurs de fonction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X