IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Initialisation de tableau de pointeurs de fonction dans le constructeur


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut Initialisation de tableau de pointeurs de fonction dans le constructeur
    Bonjour à tous,

    Alors voilà, je débute vraiment en C++, mais ayant touché un peu aux tableaux de pointeurs sur fonctions en C, je souhaiterais pouvoir faire de même en C++.

    Pour illustrer la chose, un exemple de ce que je fais (j'ai mixé le hpp et cpp) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
     
    class test
    {
     
    private:
     
    	int m_var;
    	float m_vfl;
    	// etc... 
     
    public:
     
    	test();
    	test(int a, float b);
    	~test();
     
    	int(test::*ftab[6])(const float v);
     
    	void fonction_qqe(const int i, const float v);
     
    	int fonction1(const float v);
    	int fonction2(const float v);
    	// etc...
    	int fonction6(const float v);
     
    };
     
    // le constructeur : 
     
    test::test(): m_var(0), m_vfl(0.0f) // etc...
    {
    	// initialisation du tableau de pointeur sur fonction
     
    	int(test::*ftab[6])(const float v) = { &test::fonction1, &test::fonction2, /*etc...*/ &test::fonction6 };
     
    }
     
    // et maintenant l'utilisation dans un fonction membre : 
     
     
    void test::fonction_qqe(const int i, const float v)
    {
    	float a(0.0)
     
    	a = (this->*ftab[i])(v);
     
    	// suite de la fonction
    }

    A la vue de ce code, on sais déjà qu'il est mauvais car je l'utilise exactement comme on le ferait en C (à l'exception des namepaces).
    A la compilation, l'utilisation de -Wall me dit seulement que la variable "const float v" du pointeur de fonction n'est pas utilisé. Si j'enlève l'option -Wall, ça compile, mais me sort une belle erreur de segmentation...
    Petit aparté, mes options de compilation sont -W -Wall -Wextra -Werror -O3

    J'ai bien vérifié, il n'y a aucun cas pour lequel "i" (l'index du tableau de pointeur) serait supérieur à l'indice maxi (soit 5).

    J'imagine donc que mon code est foireux dès son initialisation dans le constructeur, mais si je trouve des exemples de code sur le net, je remarque qu'à chaque fois, ces pointeurs sont initialisés en dehors des fonctions membres. Ors, j'en ai besoin au sein de ma classe uniquement.


    Une âme charitable saurait mettre le doigt sur mon (mes) erreur(s) ?

    Merci d'avance !


    EDIT : bon.... Après avoir trituré mon code, finalement, sur un erreur, ça a marché. J'ai simplement supprimé la déclaration dans le *.hpp pour la déclarée et l'initialisée dans mon *.cpp (en dehors du constructeur), et ça marche impeccable. même le -Wall ne me sort aucune erreur.... Néanmoins je suis friand de savoir comment je pourrais mieux faire. car si je veux rajouter une fonction par la suite, cela m'oblige à en modifier une autre.... Aussi, je ne suis pas fan d'initialiser cette dernière en dehors de la classe... Une idée ? Merci d'avance !

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 751
    Par défaut
    Et pourtant avec un code à la C (initialisation + déclaration d'un tableau + typedef), cela marche nickel

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #include <iostream> 
     
     
    class Test
    {
    private:
     
        int m_var;
        float m_vfl;
    //  etc... 
     
    public:
     
        Test();
    //  Test(int a, float b);
    //  ~Test();
     
    private:
     
        typedef int(Test::*type_func)(const float v);
     
        const static unsigned int NB_FUNCS = 6;
     
        type_func ftab[6];
     
    public:
     
        void fonction_qqe(const unsigned int i, const float v);
     
        int fonction1(const float v) { return 25; }
        int fonction2(const float v) { return 26; }
        int fonction3(const float v) { return 27; }
        int fonction4(const float v) { return 28; }
        int fonction5(const float v) { return 29; }
        int fonction6(const float v) { return 30; }
    };
     
     
    Test::Test(): m_var(0), m_vfl(0.0f) /* etc... */ {
        ftab[0] = Test::fonction1;
        ftab[1] = Test::fonction2;
        ftab[2] = Test::fonction3;
        ftab[3] = Test::fonction4;
        ftab[4] = Test::fonction5;
        ftab[5] = Test::fonction6;
    }
     
     
    void Test::fonction_qqe(const unsigned int i, const float v) {
        if (i >= Test::NB_FUNCS) { return; }
     
        float a(0.0);
     
        a = (this->*ftab[i])(v);
     
    //  suite de la fonction
     
        std::cout <<  "Test::fonction_qqe - " << a << std::endl;
    }
     
     
    int main()
    {
        Test a;
     
        for(unsigned char func = 0; func < Test::NB_FUNCS; ++func) {
            a.fonction_qqe(func, 7.25);
        }
     
        return 0;
    }

  3. #3
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    Bonjour,

    je te remercie pour ce retour. Cependant, je n'utilise pas de typedef dans mon code en C. Pour moi, c'est directement int(*fcptr[6])(float)...

    Je vais néanmoins tester le type d'implémentation que tu proposes.


    Merci !

  4. #4
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Ton problème se situe sur la ligne 35 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int(test::*ftab[6])(const float v) = { &test::fonction1, &test::fonction2, /*etc...*/ &test::fonction6 };
    Tu ne remplis pas ton tableau membre, mais en crée un autre local du même nom.
    Ce qui fait que ton tableau membre qui lui, persiste et est utilisé dans ta fonction membre fonction_qqe, n'a pas été initialisé et pointe vers des adresses totalement aléatoires.

    Tu n'aurais pas eu ce problème si tu l'avais initialisé avec tes autres membres dans la liste d'initialisation (faisable depuis la norme C++11 avec des accolades) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    test::test(): m_var(0), m_vfl(0.0f), ftab { &test::fonction1, &test::fonction2, /*etc...*/ &test::fonction6 }
    { }
    Si ton compilateur ne supporte pas C++11, tu n'auras pas d'autre choix que d'initialiser une à une les valeurs dans le corps de ton constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    test::test(): m_var(0), m_vfl(0.0f)
    {
        ftab[0] = &test::fonction1;
        ftab[1] = &test::fonction2;
        // etc.
    }
    mais je t'encourage vivement à le mettre à jour .

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BioKore Voir le message
    je débute vraiment en C++, mais ayant touché un peu aux tableaux de pointeurs sur fonctions en C, je souhaiterais pouvoir faire de même en C++
    Bonjour,

    En tant que vraiment débutant en C++, nous te conseillons (je parle au nom des autres, je sais qu'ils seront d'accord) que tu apprennes tout de suite quelque chose d'important : le C et le C++ ne partage presque qu'une syntaxe, une manière de représenter et d'accéder à la mémoire ainsi que quelques fonctions. Les philosophies sont très différentes et les codes que tu produiras avec ces 2 langages le seront donc forcément. S'il s'agit ici d'expérimenter un peu le langage, pas de problème. En revanche, si ton tableau de pointeurs de fonctions est vraiment une solution que tu envisages pour ton programme, alors je te conseille vivement de nous expliquer ton problème original (celui qui t'as mené à ce tableau de pointeurs de fonction). On sera très heureux de t'aider à une solution à l'esprit C++ (et non à l'esprit C).

    A plus !

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    std::array<std::function<int(float)>, 6>
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Bousk Voir le message
    std::array<std::function<int(float)>, 6>
    C'est effectivement la transcription la plus directe en C++ du tableau de pointeurs de fonction, mais ce n'est pas certain que ce soit la meilleure, selon ce que le BioKore essaye de faire...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Effectivement pour utiliser std::function il faudrait passer par un std::bind(&test::fonction1, *this, std::placeholders::_1), du coup ici j'y préfèrerais typedef int(test::*Func)(const float); std::array<Func, 6>
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Membre éclairé Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Par défaut
    Bonjour, et merci pour ces retours !


    N'ayant pas l'habitude du C++, lorsque j'ai créé le topic, je n'utilisais pas les listes d'initialisation (dont l'utilité était assez obscure pour moi). Maintenant que j'ai un peu pigé le truc, je passe effectivement par la liste d'initialisation, ce qui est pour le coup, tout à fait logique (même si, question esthétique, je trouve ça "moche") !

    En ce qui concerne la raison pour laquelle je veux utiliser les pointeurs de fonction, c'est assez simple : éviter de faire des switch assez conséquents, traités dans des boucles...
    Lorsque j'ai réalisé ça dans mon code en C, j'ai gagné en lisibilité et en simplicité. J'ai donc naturellement souhaité retrouver le même rapport performances / confort d'utilisation pour mon code en C++.

    Pour détailler un peu plus, mon programme initial est un réseau de neurones (sans prétention), nécessitant donc plusieurs fonctions mathématique différentes selon les neurones et selon le sens de la propagation. Je ne rentrerais pas dans le détail ici, mais en gros, j'ai 6 fonctions mathématiques possible et différentes par neurone (sur 300 neurones), et 6 fonctions permettant de calculer les dérivées des premières. Lors de l'apprentissage, il est nécessaire de faire plusieurs itérations, sur plusieurs exemples ; à chaque itération, pour chaque exemple (60000 exemples dans mon cas), on calcule la sortie de la fonction de chaque neurones, et la dérivée de ces fonctions lors du retour. En gros, on se retrouve avec, pour 300 neurones, 300*60.000 appels pour les fonctions de propagation (un switch pour 6 fonctions) et 300*60.000 appels pour la rétro-propagation (un switch sur 6 fonctions dérivées), soit 36.000.000 d'appels sur des switchs (pour une seule itération).

    La raison pour laquelle j'ai pensé aux pointeurs de fonctions est double : la principale raison est de me passer des appels aux switchs (oui, c'est peut-être bête mais je trouve que ça fait moche dans mon code...), et pourquoi pas, voir si je pouvais gagner un peu en performances. A ce jour, dans mon code en C, une itération est réalisée, selon les fonctions appelées, en ~14 secondes. Avec les pointeurs de fonction, j'ai gagné ~0.01 seconde (difficile à dire) par itération. Ça ne parait pas beaucoup comme ça mais on peut vite passer de 300 à 2000, voire 20000 neurones selon l'application que l'on souhaite, et nécessiter plusieurs milliers d'itérations sur des populations de centaines de milliers d'imputs, donc je suis dans une situation où le moindre millième de seconde gagné a son importance.

    Après, étant débutant, évidemment, je n'ai pas la prétention de faire tout au mieux, et encore moins d'avoir les capacités matérielles de calculer de grosses populations sur de gros réseaux, et il est tout à fait certain qu'il doit exister des solutions plus performantes que les pointeurs de fonction pour ce genre de choses. Cependant, souhaitant apprendre aussi pour le plaisir, je me suis dit que passer par des pointeurs de fonctions me permettrait d'apprendre et de trouver plusieurs solutions pour un seul problème.


    Je sais que le C et le C++ sont des standards différents ; c'est donc pour cela que j'aborde le C++ comme étant complètement nouveau pour moi (il est déjà très différent du C++ que j'ai eu l'occasion de bidouiller il y a 16 ans). Néanmoins, si quelque chose est faisable en C, je sais qu'il est faisable en C++ aussi (et vice/versa, même si c'est plus compliqué dans l'autre sens) ; mais là n'est pas la question.


    Merci encore pour vos retours.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/12/2009, 11h40
  2. appel pointeur sur fonction dans DLL
    Par dietrich dans le forum Windows
    Réponses: 6
    Dernier message: 24/10/2007, 21h48
  3. [BCB6]Tableau de pointeurs sur fonctions
    Par rtg57 dans le forum C++Builder
    Réponses: 6
    Dernier message: 06/10/2006, 20h49
  4. Tableau de pointeur de fonction
    Par Gryzzly dans le forum C
    Réponses: 7
    Dernier message: 31/12/2005, 10h47
  5. Tableau de pointeurs de fonctions
    Par Alp dans le forum C++
    Réponses: 7
    Dernier message: 29/10/2005, 13h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo