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 :

[c++11] Problème : fonction retournant un std::array. (A 2 dimensions)


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut [c++11] Problème : fonction retournant un std::array. (A 2 dimensions)
    Salut!

    Je suis entrain de faire une classe qui recherche les minimums et maximums en x, y et z d'un ensemble de vecteurs et qui les stocke dans un std::array à 2 dimension. (1ère dimension pour l'axe et seconde dimension pour les mins et maxs pour chaque axe)

    Jusque là pas de soucis :

    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
     
     template <std::size_t N>
        static std::array<std::array<float, 3>,2> getExtends (const std::array<Vec3f, N>& verts) {
            float minX = 0;
            float maxX = 0;
            float minY = 0;
            float maxY = 0;
            float minZ = 0;
            float maxZ = 0;
            if (verts.size() > 0) {
                minX = verts[0].x;
                maxX = verts[0].y;
                minY = verts[0].x;
                maxY = verts[0].y;
                minZ = verts[0].z;
                maxZ = verts[0].z;
            }
            std::array<std::array<float, 3>, 2> store;
            for (unsigned int i(1); i < verts.size(); i++) {
     
     
                    if (verts[i].x > maxX) {
                        maxX = verts[i].x;
                    }
                    if (verts[i].x < minX) {
                        minX = verts[i].x;
                    }
                    if (verts[i].y > maxY) {
                        maxY = verts[i].y;
                    }
                    if (verts[i].y < minY) {
                        minY = verts[i].y;
                    }
                    if (verts[i].z > maxZ) {
                        maxZ = verts[i].z;
                    }
                    if (verts[i].z < minZ) {
                        minZ = verts[i].z;
                    }
     
     
            }
            store[0][0] = minX;
            store[0][1] = maxX;
            store[1][0] = minY;
            store[1][1] = maxY;
            store[2][0] = minZ;
            store[2][1] = maxZ;
            std::cout<<"min x : "<<store[0][0]<<" max x : "<<store[0][1]<<" minY = "<<store[1][0]<<" maxY : "<<store[1][1]<<" min Z : "<<store[2][0]<<" max Z : "<<store[2][1]<<std::endl;
            return store;
        }
    J'ai une boîte de position 200, 200, 0 et de taille 120, 110, 0 et j'ai bien c'est valeurs-ci pour store[axe][borne] : (voici ce qu'il m'affiche)

    minX : 200 maX : 320 minY : 200 maxY : 310 minZ : 0 maxZ : 0.

    Le problème survient lorsque je récupère ce tableau dans une autre fonction, les valeurs ne sont alors plus bonne pour z :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    store = Computer::getExtends(points);
        std::cout<<"min x : "<<store[0][0]<<" max x : "<<store[0][1]<<" minY = "<<store[1][0]<<" maxY : "<<store[1][1]<<" min Z : "<<store[2][0]<<" max Z : "<<store[2][1]<<std::endl;
    Voici ce qu'il m'afficher :

    minX : 200 maX : 320 minY : 200 maxY : 310 minZ : 200 maxZ : 250.

    Voila merci d'avance pour l'aide.

  2. #2
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Bonjour,

    Ne retourne jamais un conteneur standard par valeur!
    Passes le en référence à ta fonction, puis modifies cette référence. Ca devrait te donner ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static void getExtends (const std::array<Vec3f, N>& verts,std::array<std::array<float, 3>,2>& minmax)
    De plus, cela devrait peut être régler ton problème vu que ta fonction est static et que tu déclares toujours ton std::array dans cette fonction.
    Homer J. Simpson


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

    Attention aux indices, tu as ceci std::array<std::array<float, 3>,2> : soit 2 tableaux de 3 float et non l'inverse !
    D'après tes lignes store[][] = ..., tu dois inverser le 2 et le 3.

  4. #4
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Winjerome a sûrement vu juste !

    Citation Envoyé par Astraya Voir le message
    Ne retourne jamais un conteneur standard par valeur !
    Pas d'accord ! Avec la sémantique de déplacement, c'est tout à fait correct de le faire. Surtout qu'on est dans un sujet explicitement C++11.
    Find me on github

  5. #5
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Pas d'accord ! Avec la sémantique de déplacement, c'est tout à fait correct de le faire. Surtout qu'on est dans un sujet explicitement C++11.
    Oui avec la sémantique de déplacement, mais qui oblige le compilateur à respecter cette règle? Le font-il tous? Pour le moment, je suis encore partisan de ne pas toujours utiliser les solutions C++11, juste parce que les compilateurs n'ont pas le même comportement ni évolution sur l'implémentation du C++11. Imagions que l'on prend l'habitude en apprenant le C++ de faire ça. Que se passe-t-il lorsque l'on passe sur un projet assez vieux qui ne supporte pas le C++11? Les réflexes ont la vie dure et vaut mieux avoir les bons je pense.

    Enfin c'est un avis personnel et ça n'engage que moi
    Homer J. Simpson


  6. #6
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Avec la move semantic, on peut retourner un conteneur de la stl par valeur sans soucis ni risque... Sauf peut-être std::array, qu'on ne peut pas déplacer de manière efficace (c'est le prix à payer pour ne pas avoir d'indirection ou d'allocation). Maintenant, la rvo ou nrvo marchera peut-être quand même, et dans ce cas le retour sera plus efficace que la passage en paramètres (qui va forcer l'initialisation à une mauvaise valeur). Et même sans ça, pour un array de taille raisonnable, ce n'est pas évident de voir une différence. Mais je tenais à signaler ce point quand même. Je dirais que seule la mesure pourra donner une bonne information.
    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.

  7. #7
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Oui avec la sémantique de déplacement, mais qui oblige le compilateur à respecter cette règle? Le font-il tous? Pour le moment, je suis encore partisan de ne pas toujours utiliser les solutions C++11, juste parce que les compilateurs n'ont pas le même comportement ni évolution sur l'implémentation du C++11.
    La norme est là pour ça . La plupart des compilateurs du marché sont assez bien avancés sur le C++11, et cela inclue la sémantique de déplacement. Pour moi, cela fait partie du travail du développeur de savoir ce que son compilateur implémente correctement ou pas.

    Quant à faire des mesures pour voir ce qui est plus efficace : oui, à condition qu'on soit dans une phase d'optimisation, ce qui ne semble pas être le cas ici. Je dirais qu'on est encore dans la phase ou l'on écrit le code le plus expressif possible.
    Find me on github

  8. #8
    Invité
    Invité(e)
    Par défaut
    Mon compilateur est un tdm-gcc 4.8.1. (32 bits)
    Je pense qu'il supporte bien les fonctionnalités du c++11 donc.

    J'ai du faire un erreur dans les indices car pour des tableaux 2*2 ça marche sans problème.

    PS : ha oui en effet c'est std::array<std::array<float, 2> 3> et pas std::array<std::array<float, 3> 2> (je confond toujours)

    Problème résolu, merci.
    Dernière modification par Invité ; 14/04/2014 à 15h24.

  9. #9
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Je ne dis pas de ne pas utiliser le move alors que l'on pourrais l'utiliser.
    Mais avant tout, il est bon de savoir si le compilateur est capable de le faire.
    Car oui il y a des versions de gcc qui ne le font pas. Des versions customs, comme pour les consoles de salon par exemple, et la bas le code ne fonctionne plus.
    Ou alors pour de l'embarqué avec une version qui ne l'intègre pas etc..
    Donc la NRVO n'est pas une panacée existant partout et à toujours utiliser.

    Mais c'est quand même une fonctionnalité cool, je dis pas le contraire.
    Homer J. Simpson


  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    En tout cas, on est loin de :

    Citation Envoyé par Astraya Voir le message
    Ne retourne jamais un conteneur standard par valeur

  11. #11
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

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

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Bonjour,

    Pour tout ce qui est calcul d'enveloppe/bbox/extent, il y a une principe assez pratique qui revient dans de nombreuses bibliothèques : expandToInclude

    Je profite du sujet pour me mettre à jour sur C++11 et voir comment je pourrais mettre à jour certains codes. Voici ce que ça donnerait sur mes stocks :

    * Un interval au sens [lower,upper] :

    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
     
    template < typename T >
    class Interval {
    public:
    	typedef T value_type ;
     
    	static_assert( std::numeric_limits< value_type >::has_quiet_NaN, "T doit posséder le concept de NaN (gestion de empty)" ) ;
     
    	Interval():
    		_lower( std::numeric_limits< value_type >::quiet_NaN() ),
    		_upper( std::numeric_limits< value_type >::quiet_NaN() )
    	{
    	}
     
    	Interval( const value_type & value ):
    		_lower( value ),
    		_upper( value )
    	{
    	}
     
    	Interval( const value_type & v1, const value_type& v2 ):
    		_lower( std::min(v1,v2) ),
    		_upper( std::max(v1,v2) )
    	{
    	}
     
    	void expandToInclude( const value_type & v ) {
    		if ( isEmpty() ){
    			_lower = v ;
    			_upper = v ;
    		}else if ( ! isNaN(v) ){
    			_lower = std::min( _lower, v ) ;
    			_upper = std::max( _upper, v ) ;			
    		}
    	}
     
    	void expandToInclude( const Interval & other ) {
    		expandToInclude( other.lower() ) ;
    		expandToInclude( other.upper() ) ;
    	}
     
    	bool isEmpty() const {
    		return isNaN(_lower) ; 
    	}
     
    	const value_type & lower() const {
    		return _lower; 
    	}
     
    	const value_type & upper() const {
    		return _upper; 
    	}
     
    private:
    	value_type _lower ;
    	value_type _upper ;
    };
    * Une Box définie par des Interval sur les différentes dimensions

    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
     
    template < typename T, unsigned int N >
    class Box {
    public:
    	typedef Interval< T >    interval_type ;
    	typedef std::array<T,N>  vector_type ;
     
    	void expandToInclude( const vector_type & v ) {
    		for ( size_t i = 0; i < N; i++ ){
    			_bounds[i].expandToInclude( v[i] ) ; 
    		}
    	}
     
    	const interval_type & operator [] ( const unsigned int & i ) const {
    		return _bounds[i];
    	}
    	interval_type & operator [] ( const unsigned int & i ) {
    		return _bounds[i];
    	}
     
    private:
    	std::array< interval_type, N > _bounds ;
    };
    * 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
     
    typedef std::array<float,3> Vec3f ;
    typedef Box<float,3>         Box3f ;
     
    typedef Box<int,3>            Box3i ;
     
    int main(){
    	std::vector< Vec3f > points = {
    		{1.0f,3.0f,6.0f},
    		{3.0f,2.0f,8.0f}
    	} ;
     
    	Box3f box ;
    	for ( const Vec3f & point : points ){
    		box.expandToInclude( point ) ;
    	}
    	std::cout << "xmin, ymin, zmin : " ;
    	std::cout << box[0].lower() << " " << box[1].lower() << " " << box[2].lower() << std::endl;
     
    	std::cout << "xmax, ymax, zmax : " ;
    	std::cout << box[0].upper() << " " << box[1].upper() << " " << box[2].upper() << std::endl;	
     
    	return 0 ;
    }
    PS :
    - Tu peux supporter des "expandToInclude" avec des vecteurs de dimension inférieure à celle de la boite
    - Tu peux raffiner avec des "Box::expandToInclude(other: Box)"
    - Pour le isNaN, je n'ai rien de mieux que ça de mon côté...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template < typename T >
    bool isNaN( const T& value ){
    	return value != value ; 
    }

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 31/01/2008, 08h34
  2. Problème fonction retournant type complexe.
    Par mihaestii dans le forum SQL
    Réponses: 3
    Dernier message: 27/08/2007, 14h33
  3. Réponses: 22
    Dernier message: 06/11/2006, 19h31
  4. Réponses: 6
    Dernier message: 14/02/2006, 11h29

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