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 :

choix d'une fonction en argument : lambda, class ou structure ? #optimisation


Sujet :

C++

  1. #1
    Membre tr�s actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : Consultant informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par d�faut choix d'une fonction en argument : lambda, class ou structure ? #optimisation
    Bonjour, je bosse sur de l'algorithmie et je suis confronter � un probl�me de conception et d�optimisation.

    Comment faire pour choisir une fonction en param�tre de mani�re efficace ?
    En gros je veux un truc du genre :

    L'utilisateur de la lib d�finie :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    Algo *test = new algo(cosinus); // le cosinus provenant d'une enum
    Et dans le constructeur de Algo, un truc du genre:
    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
     
    enum functionEnum
    {
        cosinus,
        sinus,
        tangent
    };
     
    class Algo
    {
        public :
     
        Algo(functionEnum e)
        {
             if(e == cosinus)
                 func = [](float x) { return cos(x); };
     
             else if(e == sinus)
                 func = [](float x) { return sin(x); };
     
             else if(e == tangent)
                func = [](float x) { return tan(x); };
         }
     
        private :
     
        float func;
    }
    Cela fonctionne tr�s bien mais j'aimerais externaliser mes fonctions dans un autre ficher pour des raison de lisibilit�. Dois-je faire une class static avec pour stocker mes fonctions ? Du coup, plus besoin de lambda ? Ou alors est-il plus propre de faire une class d�riv� d'Algo pour chaque fonction ? Sinon je peux faire une structure contenant un pointer vers la fonction mais cela est trop car en r�alit� il s'agit de r�seaux de neurones et je ne peux pas cr�er un pointer vers une fonction par neurones, cela serait trop lourd et ferait trop de r�p�tission, non ? D'ailleurs, les lambda/pointers de fonction sont-ils stocker dans le tas ou la pile ?

    Bien �videmment cela doit rester le plus optimiser possible car les fonctions sont appel� plusieurs 100�ne de milliers de fois pas seconde.


    PS : Les cos, sin et tan ne sont ici que pour l'exemple, mes fonctions sont en r�alit� un peu plus complexes et plus nombreuses que cela et c'est aussi pour cela que je ne peux pas directement mettre mes fonctions dans ma classe Algo.
    D'ailleurs il ne s'agit pas juste d'une fonction mais d'un couple de fonction : la fonction et sa d�riv�e associ�.

    Merci d'avance pour votre aide

  2. #2
    Expert confirm�
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    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 772
    Par d�faut
    Et un truc comme cela, mais niveau performances je ne sais pas si c'est bon

    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
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    #include <iostream>
     
     
    typedef enum e_func_name {
        func_name_cosinus = 0,
        func_name_other,
        func_name_sinus,
        func_name_tangent,
        func_name_unknown,
        NB_FUNC_NAMES
    } FUNC_NAME;
     
     
    template<FUNC_NAME func_name>
    class Algo
    {
    public:
     
        void operator() () {
            std::cout << "Algo : default" << std::endl;
        }
    };
     
     
    template<>
    class Algo<func_name_cosinus>
    {
    public:
     
        void operator() () {
            std::cout << "Algo : cosinus" << std::endl;
        }
    };
     
     
    template<>
    class Algo<func_name_sinus>
    {
    public:
     
        void operator() () {
            std::cout << "Algo : sinus" << std::endl;
        }
    };
     
     
    template<>
    class Algo<func_name_tangent>
    {
    public:
     
        void operator() () {
            std::cout << "Algo : tangent" << std::endl;
        }
    };
     
     
    class Execute_Algo
    {
    public:
     
        template<FUNC_NAME func_name>
        inline void run() {
            Algo<func_name> algo;
     
            algo();
        }
     
     
        inline void run(unsigned short name) {
            switch(name) {
            case func_name_cosinus: run<func_name_cosinus>(); break;
            case func_name_sinus:   run<func_name_sinus>();   break;
            case func_name_tangent: run<func_name_tangent>(); break;
            default: run<func_name_other>(); break;
            }
        }
    };
     
     
    int main()
    {
        Execute_Algo exec;
     
        std::cout << "**** Static ****" << std::endl;
     
        exec.run<func_name_cosinus>();
        exec.run<func_name_other>();
        exec.run<func_name_sinus>();
        exec.run<func_name_tangent>();
        exec.run<func_name_unknown>();
     
        std::cout << std::endl << "**** Inside a loop ****" << std::endl;
     
        for (unsigned short name; name < NB_FUNC_NAMES; ++name) {
            exec.run(name);
        }
     
        return 0;
    }

  3. #3
    Mod�rateur

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

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par d�faut
    Ce que tu souhaites faire ressembler bigrement au design pattern "strat�gie" : https://www.tutorialspoint.com/desig...gy_pattern.htm

    Dans ton cas pr�cis (mais qui est peut-�tre trop limitant), pourquoi ne pas se contenter d'un pointeur sur fonction ?

  4. #4
    Membre tr�s actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : Consultant informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par d�faut
    Citation Envoy� par foetus Voir le message
    Et un truc comme cela, mais niveau performances je ne sais pas si c'est bon
    Merci de ta r�ponse.
    Ta solution para�t un peu complexe et ce qui me d�range beaucoup c'est le switch la fonction run.

    J'y ai r�fl�chie et es-ce que �a serait une bonne solution ?
    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
    Class Aglo
    {
        public :
     
        Algo() 
        {
            switch(name)
            {
                case func_name_cosinus: function = FuncList::cosinus(x); break;
                // etc.
            }
        }
     
       private:
     
       float function;
    }
     
    Class FuncList
    {
        public:
     
        static float cosinus = [](float x)->float
        { 
            return std::cos(x); 
        };
        // etc.
    }
    Faut encore que je vois si je dois utiliser des lambdas ou des pointers de fonction, mais en gros, j'ai une list de fonction dans une classe static et dans le constructeur de Algo je fais pointer ma variable function vers la fonction que je souhaite utiliser.

    Es-ce une bonne mani�re de faire ?

    Puis-je faire pointer une variable vers un lambda ou dois-je utiliser des pointers de fonction ?

    Citation Envoy� par Bktero Voir le message
    Ce que tu souhaites faire ressembler bigrement au design pattern "strat�gie"
    Oui, c'est � peu pr�s �a mais il est impossible de faire des interfaces en C++ ?

    Citation Envoy� par Bktero Voir le message
    Dans ton cas pr�cis (mais qui est peut-�tre trop limitant), pourquoi ne pas se contenter d'un pointeur sur fonction ?
    Effectivement je pense qu'il s'agit de la bonne solution mais je n'ai jamais utiliser des pointeurs sur fonction.
    Je fais faire une classe static regroupant des templates contenant 2 pointeurs sur fonction, la fonction ainsi que sa d�riv�e.
    et ensuite je choisirais le template dans le constructeur.

  5. #5
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ing�nieur en syst�mes embarqu�s
    Inscrit en
    Juin 2004
    Messages
    1 306
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activit� : Ing�nieur en syst�mes embarqu�s
    Secteur : High Tech - �lectronique et micro-�lectronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par d�faut
    Citation Envoy� par Matthieu76 Voir le message
    Bonjour, je bosse sur de l'algorithmie et je suis confronter � un probl�me de conception et d�optimisation.
    Je veux bien entendre que vous �tes confront� � un probl�me de conception, mais j'ai des doutes sur l'optimisation. L'optimisation � priori est la racine de tous les maux.

    Vous avez besoin de cr�er un objet dont le comportement diff�re en fonction d'une donn�e d'entr�e (le type de fonction sous-jacente). Son comportement diff�re en utilisant en interne des fonctions externes (?) pour traiter les donn�es qui lui seront fournies durant son utilisation. Je suppose que le traitement de ces donn�es est gourmand en ressources, tant en terme de m�moire que de calcul. � c�t� de �a, une unique indirection est compl�tement n�gligeable.

    Dans un premier temps, concentrez-vous sur ces �l�ments de conception pour �crire un code facile � lire, � comprendre, � maintenir, etc. Une fois cela fait, si vous rencontrez des soucis de performance, vous pourrez profiler votre application pour d�tecter o� du temps/de la m�moire est inutilement perdu.

    Plusieurs angles d'attaque s'offrent � vous :
    1. Laisser l'utilisateur de la classe Algo fournir les fonctions sous-jacentes ;
    2. D�duire les fonctions sous-jacentes en interne en fonction d'un indice d'entr�e (comme un flag).


    Pour l'option #1 :
    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
    #include <iostream>
    #include <cmath>
     
     
    // Definition
    class Algo
    {
    public:
        using function_type = double(*)(double); // une fonction prenant un double et retournant un double (par exemple)
    private:
        function_type _function;
        function_type _derivative;
    public:
        Algo(function_type function, function_type derivative) : _function(function), _derivative(derivative) {}
        double do_some_work(double value) const { return 3.0 * _derivative(value) / _function(value); }
    }; // nota: Algo pourrait être templetisé selon le type de fonction sous-jacente ; cela améliorerait même sa lisibilité
     
     
    int main()
    {
        // Usage
        auto algo_sin = Algo{std::sin, std::cos};
        std::cout << algo_sin.do_some_work(22.0/7) << "\n";
    }
    Pour l'option #2 :
    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
    #include <iostream>
    #include <cmath>
    #include <tuple>
     
    // Definition
    class Algo
    {
    public:
        enum algo_type { sinus, /*...*/ };
    private:
        using function_type = double(*)(double); // par exemple
        static function_type function(algo_type type)   { return std::get<0>(function_and_derivative(type)); }
        static function_type derivative(algo_type type) { return std::get<1>(function_and_derivative(type)); }
        static std::tuple<function_type, function_type> function_and_derivative(algo_type type)
        {
            switch (type)
            {
            case sinus: return std::make_tuple<function_type, function_type>(std::sin, std::cos);
            // ...
            }
            return std::make_tuple(nullptr, nullptr);
        }
     
        function_type _function;
        function_type _derivative;
    public:
        Algo(algo_type type) : _function(function(type)), _derivative(derivative(type)) {}
        double do_some_work(double value) const { return 3.0 * _derivative(value) / _function(value); }
    };
     
     
    int main()
    {
        // Usage
        auto algo_sin = Algo{Algo::sinus};
        std::cout << algo_sin.do_some_work(22.0/7) << "\n";
    }
    Il s'agit d'impl�mentations minimales qui sont tr�s restrictives et ne fonctionnent que si les fonctions sous-jacentes � utiliser sont d�finies comme fonctions au sens de C++. Dans le cas o� il est n�cessaire de composer des fonctions sans devoir les d�finir (par exemple pour pouvoir d�finir � la vol�e -sin � partir de sin), il sera n�cessaire d'ajouter une couche d'indirection, comme par exemple d�finir Algo::_* comme std::function<double(double)> par exemple. Cela permettrait d'�crire quelque chose comme auto algo_sin = Algo{std::cos, [](double v) { return -std::sin(v); }};. (live demo)

    Les diff�rentes options on des avantages et inconv�nients qu'il vous faudra �tudier. Dans le cas de #1, l'utilisateur de la classe peut d�finir les fonctions qu'il veut, rendant la classe plus versatile et universelle. Dans le cas #2, la classe a plus de contr�le sur l'usage qu'il en est fait, seules des fonctions pr�d�finies sont utilisables. Mais dans tous les cas, les fonctions sous-jacentes peuvent �tre d�finies dans un autre fichier source, voire dans un autre binaire. Quant � l'usage de std::function, si l'appel � operateur() � chaque traitement de donn�es a un impact mesur� comme n�gatif sur les performances de votre application, il vous est possible et mettre en cache l'indirection pour qu'elle n'ait lieu qu'une unique fois. Mais il s'agit l� d'un autre probl�me.

  6. #6
    Membre �clair�
    Inscrit en
    Avril 2005
    Messages
    1 110
    D�tails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par d�faut
    J'aurais tendance � faire simple
    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
    #include <array>
     
    typedef int (*my_2_int_operand)(int, int);
     
    int myadd(int a, int b)
    	{ return a + b; }
     
    int mysub(int a, int b)
    	{ return a - b; }
     
    int mymul(int a, int b)
    	{ return a * b; }
     
    constexpr std::array<my_2_int_operand, 3> my_2_int_funcs = { myadd, mysub, mymul };
     
    enum my_2_int_enum
    { myadd_e, mysub_e, mymul_e };
     
     
    typedef float (*my_1_float_operand)(float);
     
    float mysin(float f)
    	{ return sin(f); }
     
    float mycos(float f)
    	{ return cos(f); }
     
    float mytan(float f)
    	{ return tan(f); }
     
    constexpr std::array<my_1_float_operand, 3> my_1_float_funcs = { mysin, mycos, mytan };
     
    enum my_1_float_enum
    { mysin_e, mycos_e, mytan_e };
     
     
    int run_2_int_algo(int a, int b, my_2_int_enum e)
    	{ return my_2_int_funcs[e](a, b); }
     
    float run_1_float_algo(float f, my_1_float_enum e)
    	{ return my_1_float_funcs[e](f); }
     
     
    int main()
    {
    	int i = run_2_int_algo(5, 12, myadd_e);
    	float f = run_1_float_algo(3.14159f, mysin_e);
    	return 0;
    }
    Les fonctions dans un .cpp, les enum et la d�finition des 2 fonctions run_algo dans un .h, et ta logique d'appel ailleurs dans ton code.
    C'est � la fois lisible, simple et performant, un tableau pr�d�fini � la compilation �tant plus rapide qu'un switch au runtime.
    En supposant que j'aie compris la demande

  7. #7
    Membre tr�s actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : Consultant informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par d�faut
    Citation Envoy� par prgasp77 Voir le message
    Je suppose que le traitement de ces donn�es est gourmand en ressources, tant en terme de m�moire que de calcul. � c�t� de �a, une unique indirection est compl�tement n�gligeable.
    Bah en fait je bosse sur des r�seaux de neurones et ma fonction est appeler environ 125 millions de fois par seconde. Donc oui, il s'agit bien d'un probl�me d'optimisation ! Utilise un switch ou un if dans ma fonction est inconcevable c'est pour cela que je passe par des pointeurs de fonction. C'est �a ou alors faire une classe enfant pour chaque couple fonction/d�riv�.

    Citation Envoy� par prgasp77 Voir le message
    1. Laisser l'utilisateur de la classe Algo fournir les fonctions sous-jacentes ;
    2. D�duire les fonctions sous-jacentes en interne en fonction d'un indice d'entr�e (comme un flag).
    En gros je voudrais utiliser l'imp�mentation de la solution 1 mais ou l'utilisateur passe un enum en arguments du constructeur et dans celui-ci le pointeur sur fonction et d�fie par rapport � l'enum. (Je sais pas si je suis tr�s clair)


    Citation Envoy� par camboui Voir le message
    Les fonctions dans un .cpp, les enum et la d�finition des 2 fonctions run_algo dans un .h, et ta logique d'appel ailleurs dans ton code.
    Oui c'est exactement �a que je veux merci.

    �a me donnera donc un truc du genre :

    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
    typedef float (*myFunc)(int, int);
     
    int myAdd(int a, int b)
    	{ return a + b; }
     
    int mySub(int a, int b)
    	{ return a - b; }
     
    int myMul(int a, int b)
    	{ return a * b; }
     
    enum myFuncEnum
    { add, sub, mul };
     
    Class Algo
    {
        public :
     
        Algo(enum e, a, b)
        {
            this.a = a;
            this.b = b;
     
            if(e == add)
                algoFunc = myAdd;
     
            // etc.    
        }
     
        void run()
        {
            for(int i = 0; i < 10000; i++)
                algoFunc(a, b);
        }
     
        private :
            myFunc algoFunc;
            int a;
            int b;
     
    int main()
    {
            Algo test(10, 5, add);
            test.run();
    	return 0;
    }
    Avec surement quelques erreurs de syntaxe bien entendu

  8. #8
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ing�nieur en syst�mes embarqu�s
    Inscrit en
    Juin 2004
    Messages
    1 306
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activit� : Ing�nieur en syst�mes embarqu�s
    Secteur : High Tech - �lectronique et micro-�lectronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par d�faut
    Citation Envoy� par Matthieu76 Voir le message
    Bah en fait je bosse sur des r�seaux de neurones et ma fonction est appeler environ 125 millions de fois par seconde. Donc oui, il s'agit bien d'un probl�me d'optimisation !
    Mettons-nous d'accord sur les termes. Pour optimiser, il faut une base de comparaison. On optimise pas � partir de rien. Si la d�finition au d�but du XX�me si�cle d'optimiser �tait faire au mieux, son sens actuel et notamment en informatique est :
    Optimiser
    Rendre optimal, atteindre un optimum de production, obtenir le meilleur, selon un ensemble de crit�res, d'une chose ou d'une situation.
    Il est donc question de modification, d'am�lioration. Vous ne pouvez pas d�s la conception optimiser, il vous faut un premier jet qui aura besoin, ou non, d'optimisation. Ce que j'essaie d'exprimer plus ou moins efficacement, c'est que vous devez vous soucier des contraintes temporelles de votre impl�mentation, mais vous n'�tes pas encore en phase d'optimisation. L'optimisation � priori est la racine de tous les maux (m�me � 125 MTPS).

    Citation Envoy� par Matthieu76 Voir le message
    [J]e voudrais utiliser l'imp�mentation de la solution 1 mais ou l'utilisateur passe un enum en arguments du constructeur et dans celui-ci le pointeur sur fonction et d�fie par rapport � l'enum.
    C'est exactement ce que je d�cris dans ma seconde impl�mentation.

    Bref, je vous invite � relire mon message ; il semble que vous soyez pass� � c�t� de plein d'�l�ments importants. La question de l'obtention de pointeur de fonction � partir de types vari�s (std::function, lambda, fonctions libres...) y est par exemple trait�. Et nulle part il est question d' "[utiliser] un switch ou un if dans [votre] fonction".

  9. #9
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    Un switch �tant un simple jump, je vois pas de quoi tu as peur d'en utiliser ? Surtout � priori.
    Si tu veux vraiment des perfs, tu ne mets aucune indirection, et ta fonction serait un param�tre template de la classe.
    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.

  10. #10
    Expert confirm�
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    F�vrier 2005
    Messages
    5 509
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : France, Val de Marne (�le de France)

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : F�vrier 2005
    Messages : 5 509
    Par d�faut
    Un switch �tant un simple jump
    Heu, non, c'est au minimum une comparaison + un jump, et surtout un m�ga bordel dans les m�canismes de pr�diction de branches, le cache des instructions, des donn�es, etc...
    Tout �a pour voir que le seul moyen d'avoir des perf. convenables, c'est de faire �a dans le GPU donc avec rien de comparable � la solution "full CPU".

  11. #11
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ing�nieur en syst�mes embarqu�s
    Inscrit en
    Juin 2004
    Messages
    1 306
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activit� : Ing�nieur en syst�mes embarqu�s
    Secteur : High Tech - �lectronique et micro-�lectronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par d�faut
    Citation Envoy� par bacelar Voir le message
    un m�ga bordel dans les m�canismes de pr�diction de branches, le cache des instructions, des donn�es, etc...
    Une exp�rience personnelle � partager ? On pourrait tous en profiter j'en suis s�r.

  12. #12
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Salut,

    Moi, d'un point de vue purement conceptuel, ce qui m'inqui�te le plus, c'est d'avoir un switch ... case dans une (n'importe quelle! ) fonction.

    Car, de mani�re g�n�rale, c'est une pratique qui ne respecte pas l'OCP (Open Closed Principle, ou principe "ouvert ferm�").

    Alors, je sais: on pourrait faire valoir que "des fonctions de trigonom�trie, y en a pas des masses", que "le nombre de fonctions de trigonom�trie est clairement �tabli" (sous entendu "il y a peu de chances que l'on vienne � devoir en rajouter une par la suite"), ou encore que "le but de cette classe est de respecter le DRY, en n'ayant du code � modifier qu'� un seul endroit en cas de besoin" et qu'il n'y a donc -- a priori -- aucune raison que l'on doive aller changer le code pour pouvoir ajouter une nouvelle fonctionnalit�. Et je serai bien oblig� d'�tre d'accord face � cette objection...

    Seulement, j'ai un probl�me avec le nom de la classe utilis� lors de la question initiale : Algo (pour "algorithme", d'ailleurs pourquoi �lider le nom ). Car le nom d'une classe indique l'utilisation que l'on peut en faire. Or, "algorithme", c'est comme "manager" ou "gestionnaire": ce sont des termes particuli�rement vagues, qui nous incitent tr�s facilement � prendre de mauvaises d�cisions.

    Ainsi, si un jour, tu en viens � vouloir ajouter la fonctionnalit� de calcul de la racine carr�e (pour respecter le prototype de la fonction), tu as de grandes chances d'en arriver � te dire que "ben, finalement, ma classe Algo est id�al pour remplir ce besoin", et de d�cider d'ajouter cette fonctionnalit� � ta classe Algo, dont tu avais au d�part consid�r� qu'elle n'ex�cuterait ... que des fonctions de trigonom�trie.

    Et, bien sur, cela t'obligeras � ... aller modifier du code qui avait pourtant �t� valid�, ce qui est en complet d�saccord avec l'OCP.

    Cela peut donc parraitre idiot, mais j'aurais sans doute moins d'objection si cette classe s'appelait Trigono (ou Trigo), car, au moins, cela �viterait le risque de prendre de mauvaises d�cisions

    Enfin, le service rendu par ta classe consiste s'emble-t-il -- quoi qu'il arrive -- � faire appel � des fonctions existantes, et l'utilisation d'un callback semble donc parfaitement justifi�e, l'id�al �tant sans doute de fournir, tout simplement, la fonction qui devra �tre appel�e au constructeur de ton instance, sous une forme qui pourrait �tre proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Algo{
    public:
        /* j'utilise les fonctionnalités apparues en C++11... je ne m'inquiète pas des performances */
       using callback_t = std::function<double (double)>
       Algo(callback_t callee):callee_{callee}{
       }
       double callMe(double value) const{
           return callee_(value);
       }
    private:
       callback_t callee_;
    };
    (code non test�)
    De cette mani�re, tu pourrais envisager d'�crire un code proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    /* converti des degrés en radians ;) */
    double degToRad(double);
    int main(){
        Algo sinus(std::sin);
       /* OU OU OU */
       Algo specificThing([](double d) {return /* ... */ };);
       /* ... */
       auto result1 = sinus.callMe( degToRad(35.11));
       auto result2 = specificThing(3.1415926);
       /*...*/
    }
    Note d'ailleurs que la classe Algo pourrait tout aussi bien prendre une forme template, histoire d'accepter "n'importe quel type num�rique"
    A m�diter: La solution la plus simple est toujours la moins compliqu�e
    Ce qui se con�oit bien s'�nonce clairement, et les mots pour le dire vous viennent ais�ment. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 f�vrier 2014
    mon tout nouveau blog

  13. #13
    Expert confirm�
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    F�vrier 2005
    Messages
    5 509
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : France, Val de Marne (�le de France)

    Informations professionnelles :
    Activit� : D�veloppeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : F�vrier 2005
    Messages : 5 509
    Par d�faut
    Alors, je sais: on pourrait faire valoir que "des fonctions de trigonom�trie, y en a pas des masses"
    Je trouve qu'il y a d�j� la dose juste dans la norme en terme de fonctions num�rique:
    http://fr.cppreference.com/w/cpp/numeric/math

    C'est pas une application de g�om�trie mais une simulation de neurones, les fonctions de mod�lisation de ces machins sont pl�thores.

  14. #14
    Mod�rateur

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

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par d�faut
    Citation Envoy� par Matthieu76 Voir le message
    Oui, c'est � peu pr�s �a mais il est impossible de faire des interfaces en C++ ?
    C'est �videmment possible

    Ce n'est pas exactement une interface au sens Java mais c'est tr�s proche. Il s'agit d'une classe ne d�finissant que des fonctions membres virtuelles pures. Exemple :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    class Algorithm
    {
    public:
        virtual T compute(U u, V v) = 0;
    };
    Et voil� !

    PS : comme toute classe de base, elle devrait avoir un destructeur virtuel (ne faisant rien ici).

  15. #15
    Membre tr�s actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : Consultant informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par d�faut
    Citation Envoy� par prgasp77 Voir le message
    Ce que j'essaie d'exprimer plus ou moins efficacement, c'est que vous devez vous soucier des contraintes temporelles de votre impl�mentation, mais vous n'�tes pas encore en phase d'optimisation.
    Pour l'instant je change le contenue de ma fonction directement dans le code puis je recompile. Je cherche une solution qui ne me co�terais pas plus que l'appel d'une fonction donc oui on peut dire que je suis en phase d�optimisation.

    Et puis je trouve �a d�bile de ne pas r�fl�chir � l�optimisation d�s le d�but !

    J'ai des bouts de code o� je me suis dis "on verra plus tard pour l'optimisation" et l'optimisation m'a fait changer toute l'architecture de mon programme ce qui m'a fait perdre beaucoup de temps alors que si j'avais r�fl�chie � l'optimisation au d�but j'aurais p� �viter de rechanger une partie de mon code.



    Citation Envoy� par koala01 Voir le message
    Moi, d'un point de vue purement conceptuel, ce qui m'inqui�te le plus, c'est d'avoir un switch ... case dans une (n'importe quelle! ) fonction.
    Je ne vois pas en quoi cela g�ne d'avoir juste un switch dans le constructeur de ma classe pour changer des trucs en fonction de mon param�tre d'entr�e.

    Citation Envoy� par koala01 Voir le message
    cela t'obligeras � ... aller modifier du code qui avait pourtant �t� valid�, ce qui est en complet d�saccord avec l'OCP.
    Roh ... �a va c'est juste un cas � rajouter dans le switch quand j'ajoute une fonction c'est pas la mort ! Et puis si on devait vraiment �tre en parfaite accord avec tout les principes de code on d�velopperait plus rien ... Je vais pas faire un code 10 fois plus compliquer et moins clair et optimiser juste pour ne pas avoir � rajouter 1 ligne dans mon constructeur quand j�ajouterais une fonction tous les 36 du mois.

    Citation Envoy� par koala01 Voir le message
    des fonctions de trigonom�trie, y en a pas des masses
    Citation Envoy� par koala01 Voir le message
    j'ai un probl�me avec le nom de la classe utilis�
    Nan mais r�fl�chie 2 secondes, ma classe ne s'appelle pas r�ellement Algo et n'impl�mente pas des fonction trigonom�triques, mon code est plus complexe que �a. J'ai fait �a pour �tre plus clair et puis si j'avais expliqu� en d�tail mon code, tout le mode aurait fait des remarques sur le reste de mon code et personne n'aurait r�pondu � ma question exactement comme tu viens de le faire en critiquant le nom de ma classe. (Je dis �a par exp�rience )

    En r�alit� dans mon code j'ai une classe NeuralNetwork contenant un vecteur de Perceptron aussi appeler neurones et c'est la fonction d'activation ainsi que la d�riv�e de fonction d'activation de mes perceptrons que j'aimerais choisir, avec une enum, � la cr�ation de mon r�seaux de neurones. Il est vrai que j'aurais peut-�tre d� commencer par l�. Et c'est pour cela que les pointeurs sur fonction s'y pr�te bien, comme �a tous mes neurones pointent vers la m�me fonction d'activation. Enfin j'aurais une fonction d'activation diff�rente par couche mais �a c'est une autre histoire ...



    Citation Envoy� par Bktero Voir le message
    Il s'agit d'une classe ne d�finissant que des fonctions membres virtuelles pures.
    Merci j'avais pas pens� � �a, j'avais oublier le mot cl� virtual. Du coup est-il possible de faire des m�thodes qui prenne en argument une classe "interface" et de passer un enfant en argument ... Euh ... Bah oui �videmment je suis b�te !
    M�me si dans mon cas cela ne m'aide pas beaucoup car �a serait trop lourd de refaire une classe pour chaque fonction alors que tout le reste de ma classe ne change pas d'un poil.



    Bon, j'ai pris ma d�cision, je vais faire une classe abstraite contenant des pointeurs sur fonction et je vais faire un gros switch dans le constructeur de ma classe algo pour allou� la bonne fonction � la cr�ation de mon objet.

    Ah et si quelqu'un pourrait m'expliquer comment son g�rer les pointeurs de foctions en RAM �a serait tr�s sympa. Es-ce que le code de la fonction et copier du tas � la pile lors de l�ex�cution ?

    MERCI � TOUS.

  16. #16
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Citation Envoy� par Bktero Voir le message
    PS : comme toute classe de base, elle devrait avoir un destructeur virtuel (ne faisant rien ici).
    Pas forc�ment :

    Si nous sommes bien dans le cadre d'une interface au sens "javaiste" du terme (comprend : d'une classe dont le seul but est de permettre d'exposer des fonctions dont le comportement doit �tre d�fini par celui qui les utilise), tu peux tout � fait envisager de placer le destructeur (non virtuel) dans l'accessibilit� prot�g�e, ainsi que le constructeur, selon toute vraisemblance.

    Car il s'agit alors de classes:
    • dont on ne veut pouvoir cr�er une instance qu'au travers des classes d�riv�es (ce qui est une raison suffisante pour placer le constructeur dans l'accessibilit� prot�g�e
    • dont on veut refuser la cr�ation d'une instance en tant que telle (m�me si la pr�sence d'une fonction virtuelle pure suffirait � cet effet)
    • dont on ne veut surtout pas permettre � l'utilisateur la destruction d'une instance d�riv�e si elle n'est connue que "en tant qu'instance de la classe de base"

    Ce qui nous donnerait au final quelque chose comme
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class MyInterface{
    public:
        /* tant qu'à faire, enfonçons un peu le clou de la sémantique d'entité */
       MyInterface(MyInterface const & ) = delete;
       MyInterface & operator = (MyInterface const &) = delete;
       virtual ReturnType do_something()/* const*/ = 0:
    protected:
       /* seules les classe dérivées auront accès au constructeur et au destructeurs 
        * (qui ne font rien d'autre que leur comportement par défaut, en l'occurrence)
        */
       MyInterface() = default;
       ~MyInterface = default;
    };
    Note d'ailleurs que l'on pourrait s'�carter un peu de cette restriction propre � java (et � d'autres langages) qui veut qu'une interface ne soit compos�e d'aucune donn�e, et que les fonctions que l'on y d�clare seront d�s lors forc�ment virtuelles pures.

    Notre interface pourrait, en effet, �tre repr�sent�e sous la forme d'une classe tout � fait classique, avec des donn�es membres qui lui sont propres, et n�cessaires au bon fonctionnement des services qu'elle expose; par exemple
    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
    class Movable{
    public:
        /* tant qu'à faire, enfonçons un peu le clou de la sémantique d'entité */
       Movable(Movable const & ) = delete;
       Movable & operator = (Movable const &) = delete;
       /* pas besoin d'une fonction virtuelle : on définit très clairement le comportement */
       void move(Type diffX, Type diffY){
           /* il manque quelques tests "qui vont bien", pour s'assurer que 
            * l'élément se dépalce "où il peut / a la capacité" d'aller ;)
            */
           pos_ = Position{pos_.x + diffX, pos.y + diffY};
       }
       /* on voudra sûrement connaître la position de l'élément */
       Position const & position() const{
           return pos_;
       }
    protected:
       /* on ne veut pas que l'utilisateur de cette classe puisse en créer une instance
        * "telle qu'elle" : il doit passer par une des classes dérivées
        */
       Movable() = default;
       ~Movable() = default;
    private:
        /* la donnée membre qui permet le bon fonctionnement des services exposés */
        Position pos_;
     
    }
    L'�norme avantage, par rapport � la premi�re solution, c'est que l'on ne sera pas oblig� de d�finir le comportement (qui a tout lieu d'�tre identique) des fonctions expos�es pour chaque classe pour laquelle nous souhaitons profiter de la possibilit� de mouvement
    @bacelar : merci, cela semble confirmer mon point de vue

    @Matthieu76
    Roh ... �a va c'est juste un cas � rajouter dans le switch quand j'ajoute une fonction c'est pas la mort ! Et puis si on devait vraiment �tre en parfaite accord avec tout les principes de code on d�velopperait plus rien ... Je vais pas faire un code 10 fois plus compliquer et moins clair et optimiser juste pour ne pas avoir � rajouter 1 ligne dans mon constructeur quand j�ajouterais une fonction tous les 36 du mois.
    C'est justement ce que je tentais d'expliquer: oui, bien sur, ce n'est pas "catastrophique", mais, d'un point de vue purement conceptuel, le simple fait de devoir modifier du code qui fonctionne pour pouvoir rajouter une fonctionnalit� est une erreur.

    Or, dans l'ordre "logique" des choses:
    1. on veille d'abord et avant tout � ce que la conception soit correcte
    2. ce n'est qu'une fois que l'on a une conception correcte que l'on prend en compte les sp�cificit�s du langage

    Par exemple, ce n'est pas parce que C++ accepte l'h�ritage multiple, ou parce qu'il permet de d�clarer une fonction virtuelle que l'on red�fini dans une accessibilit� plus permissive (ou moins permissive) que l'accessibilit� dans laquelle elle a �t� d�clar�e au d�part que l'on peut dire "LSP ne nous permettrait pas cette relation d'h�ritage, mais comme C++ l'autorise, pourquoi s'en priver "

    En gros, si un principe conceptuel te donne un NO-GO, tu arr�te ta r�flexion dans la direction que tu avais prise, et tu cherche "une autre solution"
    Nan mais r�fl�chie 2 secondes, ma classe ne s'appelle pas r�ellement Algo et n'impl�mente pas des fonction trigonom�triques, mon code est plus complexe que �a. J'ai fait �a pour �tre plus clair et puis si j'avais expliqu� en d�tail mon code, tout le mode aurait fait des remarques sur le reste de mon code et personne n'aurait r�pondu � ma question exactement comme tu viens de le faire en critiquant le nom de ma classe. (Je dis �a par exp�rience )
    A vrai dire, je n'avais pas lu ton message en entier et je m'�tais arr�t� au code

    Mais tout cela n'est jamais qu'une raison de plus qui devrais t'inciter � respecter les principes SOLID (car j'ai parl� du O, mais les quatre autres ont aussi leur importance )
    A m�diter: La solution la plus simple est toujours la moins compliqu�e
    Ce qui se con�oit bien s'�nonce clairement, et les mots pour le dire vous viennent ais�ment. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 f�vrier 2014
    mon tout nouveau blog

  17. #17
    Mod�rateur

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

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par d�faut
    Citation Envoy� par Matthieu76 Voir le message
    Merci j'avais pas pens� � �a, j'avais oublier le mot cl� virtual. Du coup est-il possible de faire des m�thodes qui prenne en argument une classe "interface" et de passer un enfant en argument ... Euh ... Bah oui �videmment je suis b�te !
    M�me si dans mon cas cela ne m'aide pas beaucoup car �a serait trop lourd de refaire une classe pour chaque fonction alors que tout le reste de ma classe ne change pas d'un poil.
    C'est tout le concept du pattern Strat�gie. Tu as besoin d'un nouveau comportement � passer en param�tre du constructeur de NeuralNetwork ? Et bien tu impl�mentes une nouvelle fois l'interface PerceptronActivator et sa seule methode activate(). Enfin, �a c'est en Java : en C++, passer un std::function fait tr�s bien l'affaire quand ton interface ne contient qu'une seule m�thode !


    [Mode digression]
    Citation Envoy� par koala01
    Pas forc�ment :
    Oui. Mais bon ta technique ou ma technique, �a reste pour emp�cher la destruction polymorphique depuis un pointeur sur le type de base. J'aurais peut-�tre du pr�cis� : comme elle a une m�thode virtuelle, elle devrait avoir un destructeur virtuel.

  18. #18
    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 : 51
    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
    En C++, pour param�trer une ex�cution, tu as deux possibilit�s :
    - Un param�trage statique, qui sera d�termin� au moment o� tu �criras le code, r�solu � la compilation, et qui peut avoir un co�t nul lors de l'ex�cution.
    - Un param�trage dynamique, qui peut varier en cours d'ex�cution, et a un co�t (g�n�ralement raisonnable, mais un co�t n�anmoins).

    Pointeur de fonction, switch, design pattern strategy avec appel de fonction virtuelle entrent tous dans la cat�gorie dynamique (ainsi que std::function, que je pr�f�re g�n�ralement aux alternatives d�j� �voqu�es).

    Pour le param�trage statique, la technique � utiliser est un param�tre template. C'est par exemple ce qui est utilis� pour les algorithmes de la STL (regarde std::sort).

    Pour l'instant je change le contenue de ma fonction directement dans le code puis je recompile.
    Tu es donc dans le cas statique. Souvent, on �crit ce genre de code avec des fonctions, ce qui permet d'utiliser la d�duction de type template, et simplifie l'�criture:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    template<class Function>
    double algo(Function f, double val)
    {
      return f(2*val);
    }
     
    algo([](double d){return sin(d);}, 3.14);
    Mais si tu veux avec une classe :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template<class Function>
    class Algo
    {
      Algo(Function f) : myFunction(f) {}
      double exec(double d) { return myFunction(2*d);}
    }
     
    int g()
    {
        auto f = [](double d) {return sin(d);};
        Algo<decltype(f)> algo(f); // Avec les class template argument deduction du C++ 17, ce code doit pouvoir se simplifier en Algo algo([](double d) {return sin(d);}); mais il faut un compilateur qui gère cette nouveauté
        algo(3.14);
    }
    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.

  19. #19
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Citation Envoy� par Bktero Voir le message
    Oui. Mais bon ta technique ou ma technique, �a reste pour emp�cher la destruction polymorphique depuis un pointeur sur le type de base. J'aurais peut-�tre du pr�cis� : comme elle a une m�thode virtuelle, elle devrait avoir un destructeur virtuel.
    Ohoh... Sauf que:

    1- Un constructeur dont tu ne parle pas au compilateur sera impl�ment� automatiquement sous une forme publique et non virtuelle, ce qui nous emp�che d'utiliser la classe en question comme classe de base
    Tout simplement parce qu'un appel � delete myBase; aura pour effet de nous laisser avec un objet partiellement d�truit : seule la partie correspondant au type de base sera d�truite, mais la partie correspondant � ses classes d�riv�es (directes et indirectes) ne le sera pas.

    2- Dans le cadre sp�cifique de la cr�ation d'une interface, dont la seule utilit� est d'ajouter un (des) comportements � une classe, il ne fait normalement aucun sens de permettre la destructions des instances des classes d�riv�es alors que nous ne les connaissons que comme des (pointeur sur des) instances de cette interface:

    Pour concr�tiser mes dires, reprenons l'exemple d'une interface Movable (quelle que soit la mani�re dont on la cr�e). Tu conviendras avec moi qu'il n'y a aucun sens � avoir une fonction qui serait proche de
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    void destroy(Movable * ptr){
        delete ptr;
    }
    Car il n'y a de sens qu'� d�truire un objet concret que si on le connait soit comme �tant de son type r�el (un lion, si c'est un lion, une gazelle si c'est une gazelle) soit si on le connait comme �tant du type g�n�rique dont il est le digne repr�sentant (une classe Animal, dans ce cas particulier, pour le distinguer des insectes et des plantes).

    3- L'utilisation d'un destructeur publique et virtuel �viterait -- bien sur -- la "destruction partielle" d'un objet, mais, cela ne couvre qu'une partie du probl�me, car, comme dirait l'autre
    nous devons faire en sorte que nos classes soient facile � utiliser correctement et difficiles � utiliser de mani�re incorrecte
    En d�clarant le destructeur d'une interface comme �tant virtuel dans l'accessibilit� publique, tu laisses � l'utilisateur de ton interface la possibilit� de faire une connerie en l'utilisant; ce qui n'est jamais bon...

    Alors, bien sur, on pourra me r�torquer que "mais personne n'aurait l'id�e de d�truire un objet alors qu'il ne le conna�t sous la forme d'une de ses interfaces", et je serai bien oblig� d'admettre que la pratique est pour le moins choquante.

    Malheureusement, la loi de Finagle joue contre nous, et, s'il y a une chose que j'ai apprise depuis longtemps, c'est que l'utilisateur (quel qu'il soit, ce qui inclut tous les utilisateurs des classes que je d�veloppe, moi y compris) est un imb�cile distrait, et que, si on lui laisse l'occasion de faire une connerie, ce n'est qu'une question de temps avant qu'il ne la fasse.

    Si bien que la seule question int�ressante � se poser est "quand va-t-il faire cette connerie", et que la r�ponse sera toujours la m�me "au pire moment qui soit possible de trouver". Car il ne sert en effet � rien de perdre son temps � se demander s'il risque ou non effectivement de la faire, vu que la r�ponse est forc�ment oui

    Donc, en gros, j'estime que la seule mani�re vraiment s�curisante de cr�er une interface (ind�pendamment du fait que l'on expose des fonctions virtuelles ou non) est bel et bien d'en d�finir le destructeur dans l'accessibilit� prot�g�e, sans qu'il soit d�clar� virtuel

    PS: oui, je sais, je suis un vieux con chiant qui s'attarde sur des d�tails dont tout le monde se fout pas mal... Mais � mon age, on ne me refera plus
    A m�diter: La solution la plus simple est toujours la moins compliqu�e
    Ce qui se con�oit bien s'�nonce clairement, et les mots pour le dire vous viennent ais�ment. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 f�vrier 2014
    mon tout nouveau blog

  20. #20
    Membre tr�s actif Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (�le de France)

    Informations professionnelles :
    Activit� : Consultant informatique
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Par d�faut
    Citation Envoy� par koala01 Voir le message
    le simple fait de devoir modifier du code qui fonctionne pour pouvoir rajouter une fonctionnalit� est une erreur.
    Il est vrai que si je mets mon enum dans ma classe statique r�pertoriant mes fonctions et que j'utilise l'enum comme index d'un vector r�pertoriant mes fonction je ne devrais plus avoir besoin de modifier ma classe principale pour y ajouter une fonction. merci


    Citation Envoy� par Bktero Voir le message
    Tu impl�mentes une nouvelle fois l'interface PerceptronActivator et sa seule methode activate().
    C'est bizarre de devoir r�-impl�menter une interface alors que je veux juste changer une fonction. Il ne s'agit pas d'un autre type de neurone mais c'est le m�me neurones avec une fonction d'activate diff�rente. �a serait illogique d'un point de vue conception d'avoir des 10e de classe du genre : NeuronSinus, NeuronCosinus, NeuronTangent, NeuronSqrt, etc. M�me si elle h�rite tous d'une m�me class abstraite Perceptron, c'est plus compr�hensible je trouve d'avoir une seule classe qui prend en param�tre un pointeur de fonction. Comme �a je peux mieux regrouper et visualiser mes diff�rente fonction d'activation.


    Citation Envoy� par Bktero Voir le message
    en C++, passer un std::function fait tr�s bien l'affaire quand ton interface ne contient qu'une seule m�thode !
    Oui, mais je vais plut�t opter pour des pointeurs de fonction que des std::function car dans mon code je peux cr�er par exemple 1000 neurones qui utilise tous la m�me fonction donc autant qu'ils pointent tous sur la m�me fonction et personnellement je trouve que faire des pointeurs de std::function tout comme des pointeurs de vecteur est compl�tement absurde


    Citation Envoy� par JolyLoic Voir le message
    template<class Function>
    Merci beaucoup m�me si je ne comprends pas trop cette ligne de code m�me si je sais ce qu'est basique un template mais un template de classe alors que c'est une fonction qui varie, pas une classe, je ne comprends pas tout... (J'irais voir plus tard sur internet)

    Et encore merci � tous !

+ R�pondre � la discussion
Cette discussion est r�solue.
Page 1 sur 2 12 Derni�reDerni�re

Discussions similaires

  1. [AS2] Atteindre attribut d'une classe depuis une fonction interne a la classe
    Par Demco dans le forum ActionScript 1 & ActionScript 2
    R�ponses: 6
    Dernier message: 18/04/2006, 21h03
  2. Comment passer une fonction en argument
    Par Pades75 dans le forum Langage
    R�ponses: 4
    Dernier message: 16/02/2006, 10h34
  3. Signature d'une fonction sans argument
    Par cj227854 dans le forum C++
    R�ponses: 5
    Dernier message: 20/10/2005, 17h01
  4. creer une fonction avec arguments
    Par niglo dans le forum ASP
    R�ponses: 3
    Dernier message: 03/06/2005, 08h04
  5. Passer une fonction comme argument � une fonction
    Par Cocotier974 dans le forum G�n�ral Python
    R�ponses: 4
    Dernier message: 29/06/2004, 13h41

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