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

Langage C++ Discussion :

proposition: on stack initializable array


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2008
    Messages : 87
    Par défaut proposition: on stack initializable array
    Bonjour aux curieux

    vala j'ai programmé ca au boulot pour un certain besoin.
    Je vous prierai de respecter le code copyrighté pour le moment. (pas discuté avec le patron mais je sais qu'il ne serait pas contre une publication vu la généricité de l'outil, donc je me permet)

    c'est plus pour discuter de son utilité de toute façon.

    c'est comme boost::array, mais avec des élements non initialisés dans un premier temps, que l'on peut initialiser a tout moment.

    ceci pour éviter les trucs du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::optional< boost::array< T, N > > myArray_;
    car T doit être default-constructible !! pas bon.
    car je n'aime pas les types a moitiés construits.
    quel interet d'avoir un array optionel si ce qui est dedans est "optionel" aussi ?

    sinon il y aurait toujours:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::array< boost::scoped_ptr<T>, N > myArray_;
    pas bon non plus car utilise le heap, plus lent, et plus fragmenté !

    sinon l'inverse du début:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::array< boost::optional< T >, N > myArray_;
    j'étais content avec ca, mais les optionels stockent un bool pour connaître l'état de l'initialisation. Avec l'alignement cela donne un sizeof de 8 pour T=int !

    faute de trouver mieux, j'ai mis les mains dedans.
    voila ce que j'ai sorti:

    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
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
     
    /*** Copyright 2010 ***** S.A.R.L. ***
     * File  : utility.hpp
     * Date  : 08/01/2010
     *** ***/
     
    #ifndef UTILITY_HPP_INC_08_01_2010__252705754_
    #define UTILITY_HPP_INC_08_01_2010__252705754_ 1
     
    #include <boost/operators.hpp>
    #include <boost/mpl/for_each.hpp>
    #include <boost/mpl/range_c.hpp>
    #include <boost/utility/in_place_factory.hpp>
    #include <boost/static_assert.hpp>
    #include <new>
    #include <assert.h>
     
    #define TOOLS_ASSERT_REL(x) do{assert(x);}while(0)
     
    namespace tools
    {
        namespace mpl = boost::mpl;
     
        template< typename T, size_t N >
        struct MemoryBlock
        {
            T* addr_at(size_t pos) { TOOLS_ASSERT_REL(pos >= 0 && pos < N); return reinterpret_cast<T*>(block_) + pos; }
            T const* addr_at(size_t pos) const { TOOLS_ASSERT_REL(pos >= 0 && pos < N); return reinterpret_cast<T*>(block_) + pos; }
     
            template< size_t Pos >
            T* addr_at() { BOOST_STATIC_ASSERT( Pos >= 0 && Pos < N ); return reinterpret_cast<T*>(block_) + Pos; }
     
            template< size_t Pos >
            T const* addr_at() const { BOOST_STATIC_ASSERT( Pos >= 0 && Pos < N ); return reinterpret_cast<T*>(block_) + Pos; }
        private:
            char block_[ sizeof(T) * N ];
        };
     
        template< typename T, size_t N >
        class OnStackInitializableArray : boost::equality_comparable< OnStackInitializableArray<T,N> >
        {
            BOOST_STATIC_ASSERT(( N > 0 && "YOU CANNOT SPECIFY A NULL ARRAY" ));  // concept check
            typedef MemoryBlock< T, N > ArrayT;
            typedef OnStackInitializableArray MyType;
     
        public:
            typedef T value_type;
            typedef T* iterator;
            typedef T const* const_iterator;
     
            enum                 { static_size = N };
            static size_t size() { return N; }
            bool empty() const   { return !IsInit(); }
     
            //! default construction of all members, with compilation-time unrolled loop.
            // warning: built-in compilator resource limit of template recursion. constated at 491 on gcc4.0.1
            void Assign0()
            {
                if (init_)
                    Destruct();
                mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctor0(array_) );
                init_ = true;
            }
     
            //! construction of all members calling a constructor taking one argument of type TypeOfConstructoArgument1 (type self deducted)
            template< typename TypeOfConstructoArgument1 >
            void Assign1(TypeOfConstructoArgument1 const& value)
            {
                if (init_)
                    Destruct();
                mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctor1<TypeOfConstructoArgument1>(array_, value) );
                init_ = true;
            }
     
            //! boost in place factory version, if you want to use a constructor with more than one argument (up tp 10)
            template< typename AutoDeducedFactoryT >
            void AssignN(AutoDeducedFactoryT const& inPlaceFactory)
            {
                if (init_)
                    Destruct();
                mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctorN<AutoDeducedFactoryT>(array_, inPlaceFactory) );
                init_ = true;
            }
     
            //! destruct contained objects and switch back to uninitialized state
            void Destruct()
            {
                if (init_)
                {
                    mpl::for_each< mpl::range_c<size_t, 0, N> >( DestructMetaFctor(array_) );
                }
                init_ = false;
            }
     
            bool IsInit() const { return init_; }
     
            // access to members -- compile time index:
            template< size_t Pos >
            T& get()             { AssertIsInit_(); return *array_.template addr_at<Pos>(); }
            template< size_t Pos >
            T const& get() const { AssertIsInit_(); return *array_.template addr_at<Pos>(); }
            // access to members -- runtime index:
            T& at(size_t i)             { AssertIsInit_(); return *array_.template addr_at(i); }
            T const& at(size_t i) const { AssertIsInit_(); return *array_.template addr_at(i); }
            // by operator []:
            T& operator [] (size_t i) { return at(i); }
            T const& operator[] (size_t i) const { return at(i); }
     
            T&       front()        { AssertIsInit_(); return get<0>(); }
            T const& front() const  { AssertIsInit_(); return get<0>(); }
            T&       back()         { AssertIsInit_(); return get<N-1>(); }
            T const& back()  const  { AssertIsInit_(); return get<N-1>(); }
     
            // iteration
            iterator       begin()       { AssertIsInit_(); return array_.template addr_at<0>(); }
            const_iterator begin() const { AssertIsInit_(); return array_.template addr_at<0>(); }
            iterator       end()         { return array_.template addr_at<N-1>() + 1; }
            const_iterator end() const   { return array_.template addr_at<N-1>() + 1; }
     
    	//
            bool operator == (MyType const& rhs) const { /*todo*/ }
            MyType& operator = (MyType const& rhs) { /*todo*/ }
     
            // structors:
            OnStackInitializableArray() : init_(false) {}
            ~OnStackInitializableArray() { Destruct(); }
     
        private:
            ArrayT array_;
            bool init_;
     
            void AssertIsInit_() { TOOLS_ASSERT_REL(IsInit() && "UN-INITIALIZED ACCESS ATTEMPT"); }
     
            // == internal functors repository ==
     
            // functor that will be passed to mpl::for_each
            // it will construct-in-place with default constructor.
            struct InPlaceConstructMetaFctor0
            {
                InPlaceConstructMetaFctor0(ArrayT& arrayref) : arrayref_(arrayref) {}
                template< typename MplPlacedType > void operator () (MplPlacedType v)
                {
                    new (arrayref_.template addr_at(v)) T();  // default
                }
            private:
                ArrayT& arrayref_;
            };
     
            // version for one argument, and that will be all. newt arities of construction will use in place factories from boost.
            template< typename CtorArg1 >
            struct InPlaceConstructMetaFctor1
            {
                InPlaceConstructMetaFctor1(ArrayT& arrayref, CtorArg1 const& value) : arrayref_(arrayref), value_(value) {}
     
                template< typename MplPlacedType > void operator () (MplPlacedType)
                {
                    new (arrayref_.template addr_at<MplPlacedType::value>()) T(value_);
                }
            private:
                ArrayT& arrayref_;
                CtorArg1 const& value_;
            };
     
            // version for any other number of arguments, since they are embedded into the factory
            template< typename FactoryT >
            struct InPlaceConstructMetaFctorN
            {
                InPlaceConstructMetaFctorN(ArrayT& arrayref, FactoryT const& factory) : arrayref_(arrayref), factory_(factory) {}
     
                template< typename MplPlacedType > void operator () (MplPlacedType)
                {
                    factory_.template apply<T>(arrayref_.template addr_at<MplPlacedType::value>());
                }
            private:
                ArrayT& arrayref_;
                FactoryT const& factory_;
            };
     
            // when the class is destructed, we have to call the desctors on our objects if they are initialized.
            struct DestructMetaFctor
            {
                DestructMetaFctor(ArrayT& arrayref) : arrayref_(arrayref) {}
                template< typename MplPlacedType > void operator () (MplPlacedType)
                {
                    arrayref_.template addr_at<MplPlacedType::value>()->~T();  // call destructor
                }
            private:
                ArrayT& arrayref_;
            };
        };
    }
     
    #endif //UTILITY_HPP_INC_08_01_2010__252705754_
    exemple d'utilisation:

    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
     
    class VeryRestricted
    {
        VeryRestricted() {}
        VeryRestricted(VeryRestricted const&) {}
        VeryRestricted& operator = (VeryRestricted const& rhs) {}
    public:
        VeryRestricted(std::string myName) : n_(myName) {}
        std::string n_;
    };
     
    int main(int, char**)
    {
        typedef tools::OnStackInitializableArray< VeryRestricted, 2 >
            VRArrayT;
        VRArrayT vrArray;   
        vrArray.Assign1("youpi");  // both 2 members are init to youpi
        vrArray.get<1>().n_ = "toto";
        VRArrayT::const_iterator it = vrArray.begin();
        while (it != vrArray.end())
        {
            std::cout << it->n_ << std::endl;
            ++it;
        }
    }
    voilà qui affiche donc youpi et toto dans la console.

    les fonctionnalités:

    • assignation a tous les membres déroulée à la compilation
    • tout sur la pile
    • presque compatible conteurs STL (a peu pres comme boost::array)
    • ne fait jamais de copies d'objets temporaires inutile (in place factory pour les constructeurs a plusieurs paramètres)
    • permet au compilateur d'optimiser les accès aux cellules avec index constant.
    • aucun requirements sur le type T


    désavantages:

    • la pile est assez limitée dans un programme usuellement.
    • limité à N=491 sur le Mac du boulot, un ti peu plus sur gcc4.4 mais pas loin, et déjà 15 secondes de compilation sur mon portable.
    • pas très propre avec les Assign0,1,N (boost.preprocessor?)
    • il manque la possibilité de construire chaque cellule avec des paramètres de construction différents. (vivement C++0x et les variadics)


    vos avis ?

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Uh ?

    Je croyais que std::vector<> et std::tr1::array<> avait des constructeurs qui faisait exactement ce que fait tes méthodes Assign0 et Assign1. Si l'idée est de séprare l'initialisation des variables de la construction de conteneur, j'ai du mal à comprendre les raisons de cette séparation - puisque de toute façon le vecteur qe tu crée est intulisable tant que init_ est faux (donc tant qu'une des fonction AssignX n'a pas été appelé. Résultat, tu rends explicite quelque chose qui devrait être implicite...

    J'ai bon ?
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2008
    Messages : 87
    Par défaut
    Pas vraiment pour deux grosses raison dans un premier temps:
    1: vector alloue sur le tas.
    2: il appelle le constructeur par copie lors de l'assignation, ca fait déjà un requirements, et certaines operations necessitent default-constructible.

    c'est vrai que le besoin de cette classe est subtile mais il est réel pour éviter l'allocation de petits objets sur le tas, et éviter la fragmentation mémoire.
    vector sera plus adapté pour les tres grands tableaux. Ici nous avons de très grosses limitation : taille de pile (~4Mo souvent, voire moins) et temps de compilation + robustesse compilateur. (N>500 met gcc dans le fossé).

    l'initialization tardive est necessaire car on ne maitrise pas le moment de la construction des objets sur la pile (consruit a l'entrée du scope de la définition).


    EDIT: la raison de limiter les requirements est de pouvoir faire des classes qui sont construites pretes a l'usage. et non des classes construites par defaut non initialisées puis apres il faut appeller Create() dessus ou Load() ou autre truc du genre. c'est plus propre de spécifier de dont elle a besoin dans les arguments de son constucteur. Mon contenur permet de contenir des classes comme ca ; et même mieux, sur la pile !

  4. #4
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    4 mo pour la pile c'est beaucoup... Pour ce qui est de l'allocation de plein de petits objets ouai l'allocateur de la stl est pas super perf (gourmand en mémoire), pour ça que y'a des allocateurs maisons à passez a vector et consor. (loki a le sien).

  5. #5
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par Lightness1024 Voir le message
    Pas vraiment pour deux grosses raison dans un premier temps:
    1: vector alloue sur le tas.
    Ok, donc on prends std::t1::array<> (boost.array en fait) qui lui, alloue sur la pile.

    Citation Envoyé par Lightness1024 Voir le message
    2: il appelle le constructeur par copie lors de l'assignation, ca fait déjà un requirements, et certaines operations necessitent default-constructible.
    Etant donné qu'à un moment ou à un autre, tu effectue une copie de l'objet, tu aura nécessairement besoin d'un opérateur de copie ou d'un constructeur par copie - et je ne vois pas vraiment comment tu peux faire sans. De toute façon, si tu défini un operator=(), il est recommandé de définir aussi un constructeur par copie et un destructeur. C'est la règle des 3, qui a bien des raisons d'être.

    default-constructible est nécessaire pour std::vector<>::resize() et quelques autres fonctions. Je ne crois pas que ça soit nécessaire pour std::tr1::array<> si tu utilise le bon constructeur - mais je peux me tromper.

    Citation Envoyé par Lightness1024 Voir le message
    c'est vrai que le besoin de cette classe est subtile mais il est réel pour éviter l'allocation de petits objets sur le tas, et éviter la fragmentation mémoire.
    Un std::vector<> et un std::tr1::array<> peuvent être équivalent. Personne n'a l'obligation de faire varier en taille un vecteur créé. Au moment de la construction, on peut le créer avec une taille non nulle - et ne plus rien toucher après. Il n'y aura pas de fragmentation mémoire.

    Citation Envoyé par Lightness1024 Voir le message
    vector sera plus adapté pour les tres grands tableaux. Ici nous avons de très grosses limitation : taille de pile (~4Mo souvent, voire moins) et temps de compilation + robustesse compilateur. (N>500 met gcc dans le fossé).
    La lourdeur de std::vector<> se fait un peu moins sentir lorsque le vecteur est gros, mais ce n'est clairement pas une nécessité. Au contraire, un petit std::vector<> aura une chance de tenir dans une ligne de cache.

    Citation Envoyé par Lightness1024 Voir le message
    l'initialization tardive est necessaire car on ne maitrise pas le moment de la construction des objets sur la pile (consruit a l'entrée du scope de la définition).
    Pour être honnête, c'est le point qui me chagrine le plus dans ton code - notamment parce que si tu l'enlève, tu retombes grosso-modo sur std::tr1::array<> (qui, je le rappelle, va être poussé dans le namespace std pour C++0x).

    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
     
    struct c
    {
      int a_, b_, c_;
      c(int a, int b, int c) : a_(a), b_(b), c_(c) { }
    };
     
    // si on ne fait pas la distinction pile/tas...
    void f()
    {
      // pas besoin du constructeur par défaut de c
      // ça tombe bien, il n'y en a pas.
      std::vector<c> v1(10, c(1, 2, 3)); 
     
      // ou:
      std::vector<c> v11;
      v11.reserve(10); // la mémoire est allouée, mais les objets ne sont 
                             // pas construits :: (v11.size() == 0)
      for (std::size_t i=0; i<v11.capacity(); ++i)
      {
        v11.push_back(c(rand(), rand(), rand());
      }
      // toujours pas besoin du constructeur pas défaut dans ce code.
     
      // ce code est vaguement équivalent à : 
      ta_class_au_nom_etrange<c,10> v2;
      v2.Assign1(c(1,2,3));
     
      // à noter qu'après coup on peut aussi faire :
      v1.assign(10, c(4,5,6));
     
      // un équivalent meilleur serait d'utiliser tr1::array<>, mais
      // cette dernière classe demande réellement un constructeur
      // par défaut, alors qu'il aurait été relativement simple de ne 
      // pas en demander un. On peut pas tout le temps tout avoir...
      // en gros : il manque un constructeur à tr1::array<>.
    }
    Quand au timing de construction de l'objet :
    * avant sa déclaration, il ne doit pas être construit.
    * après sa déclaration, son constructeur doit avoir été appelé.

    Dans un tableau, les éléments sont créés dans l'ordre ascendant des indices (et ils sont détruit dans l'ordre inverse).

    Donc je ne vois pas ce qui n'est pas maitrisé ici...

    Citation Envoyé par Lightness1024 Voir le message
    EDIT: la raison de limiter les requirements est de pouvoir faire des classes qui sont construites pretes a l'usage. et non des classes construites par defaut non initialisées puis apres il faut appeller Create() dessus ou Load() ou autre truc du genre. c'est plus propre de spécifier de dont elle a besoin dans les arguments de son constucteur. Mon contenur permet de contenir des classes comme ca ; et même mieux, sur la pile !
    Là c'est un problème d'architecture. On ne résout pas les problèmes d'architecture avec du code - ça en marche pas, même si ça fait semblant (et des fois, ça fait super bien semblant).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  6. #6
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Petite appartée pour dire que cette discussion (et notamment le besoin exprimé initialement) me fait fortement penser a la EASTL -- document passionnant a lire pour peu qu'on s'interesse a la STL et qu'on connaisse les contraintes du jeu vidéo -- qui avait (si je me souviens bien) déclenché quelques réactions intéréssantes et opposées à l'époque. D'un coté ceux qui étaient d'accord avec la plupart des points exposés dans le document (critiquant donc la STL de manière très technique, expliquant des cas pratiques) ; de l'autre coté pas mal de gens a priori très expérimentés globalement d'accords pour dire que ce qui est décrit dans le document était "naïf"...

    Voilà, fin d'appartée.

  7. #7
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par Klaim Voir le message
    D'un coté ceux qui étaient d'accord avec la plupart des points exposés dans le document (critiquant donc la STL de manière très technique, expliquant des cas pratiques) ; de l'autre coté pas mal de gens a priori très expérimentés globalement d'accords pour dire que ce qui est décrit dans le document était "naïf"...
    Ce "problème" de la STL n'est pas nouveau, et n'est pas spécifique au monde du jeu vidéo : j'ai exactement les mêmes problèmes dans l'embarqué temps réel, et pour les mêmes raisons... Ce qui fait que j'ai en général les cas suivants :
    • Code non-critique et/ou de configuration : utilisation de la STL pour faire rapide sans se casser la tête trop fort.
    • Code critique : exécution sommaire de la STL au profit de structures parfois calquées sur la STL, parfois non, mais offrant des performances supérieures.
    Un "tort" courant, c'est de croire que la STL est optimale, ce qui est très largement faux. La STL est simplement la meilleure implémentation générique, mais se fait battre assez facilement par des implémentations spécifiques. Le tout est de savoir si l'on doit toucher souvent au code ou non, car le code spécifique est bien plus long à adapter / remanier bien entendu.

    Si l'on oublie de préciser "algorithme générique" et "algorithme spécifique" dans les discussions pro / anti STL, c'est directement du troll velu... Et en les précisant, la réponse est immédiate : le générique gagne sur la maintenabilité, le spécifique gagne sur les performances. Il n'y a plus qu'à choisir ce que l'on privilégie...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  8. #8
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Je me suis amusé à refaire une petit code d'essai:
    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 <string>
    #include <iostream>
    class VeryRestricted
    {
    	VeryRestricted() {}
    	VeryRestricted(VeryRestricted const&) {}
    	VeryRestricted& operator = (VeryRestricted const& rhs) {}
    public:
    	VeryRestricted(std::string const & myName, unsigned id): n_(myName), id_(id) {}
    	std::string n_;
    	unsigned id_;
    };
     
    class VeryRestrictedFactory
    {
    	std::string const & n_;
    	unsigned id_;
    public:
    	VeryRestrictedFactory(std::string const & myName, unsigned id): n_(myName), id_(id) {}
    	template<typename T>
    	void* apply(void* address) const
    	{
    		return new(address) T(n_, id_);
    	}
    };
     
    void stackarraytest()
    {
    	typedef tools::OnStackInitializableArray< VeryRestricted, 5 >
    		VRArrayT;
    	VRArrayT vrArray;   
    	// using boost factory
    	vrArray.AssignN(boost::in_place("youpi", 25));
    	vrArray.get<1>().n_ = "toto";
    	VRArrayT::const_iterator it = vrArray.begin();
    	while (it != vrArray.end())
    	{
    		std::cout << it->n_ <<" - " << it->id_ << std::endl;
    		++it;
    	}
    	// using custom factory
    	vrArray.AssignN(VeryRestrictedFactory("caramba", 15));
    	it = vrArray.begin();
    	while (it != vrArray.end())
    	{
    		std::cout << it->n_ <<" - " << it->id_ << std::endl;
    		++it;
    	}
    }
    Non rien, c'est juste un petit exercice de factory pour mon apprentissage personnel

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2008
    Messages : 87
    Par défaut
    Eh oui.

    appartée:
    J'aurais bien voulu un concept_check qui vérifie que le type template de la méthode AssignN est bien une factory de boost mais je vois pas trop comment faire. SFINAE avec methode apply ? mais ca reste suffisamment permissif pour accepter ta VeryRestrictedFactory; remarque, pourquoi pas car elle respecte le concept.
    ou alors, solution 2, il faudrait que boost::in_place retourne un type qui hérite de boost::factory_model (classe de mon imaginaire fantasmagorique) et puis on aurait qu'a tester boost::is_base_of< T, boost::factory_model >::value un truc du genre....

  10. #10
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Je viens de remarquer que boost::optional n'accepte pas les factory custom. Elles doivent dériver de boost::in_place_factory_base (qui est vide ).
    Si ça peut t'inspirer, bien que je ne trouve pas ces "concept check" comme tu les appeles très utiles dans ces cas-ci...

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2008
    Messages : 87
    Par défaut
    Citation Envoyé par camboui Voir le message
    Je viens de remarquer que boost::optional n'accepte pas les factory custom. Elles doivent dériver de boost::in_place_factory_base (qui est vide ).
    Si ça peut t'inspirer, bien que je ne trouve pas ces "concept check" comme tu les appeles très utiles dans ces cas-ci...
    Ah ouais, ah ben voilà les concepteurs de boost pensent comme moi.

Discussions similaires

  1. Array.prototype.length ? stack overload.
    Par SpaceFrog dans le forum Bibliothèques & Frameworks
    Réponses: 29
    Dernier message: 25/08/2006, 15h09
  2. Remerciements, propositions et commentaires
    Par HCath dans le forum Discussions diverses
    Réponses: 57
    Dernier message: 24/08/2006, 10h22
  3. TStringList en array of string
    Par JediKerian dans le forum Langage
    Réponses: 2
    Dernier message: 20/03/2003, 15h37
  4. Réponses: 2
    Dernier message: 23/02/2003, 00h49
  5. passage en paramètre d'un array dynamique 2D
    Par Guigui_ dans le forum Langage
    Réponses: 4
    Dernier message: 27/11/2002, 19h47

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