Partage
  • Partager sur Facebook
  • Partager sur Twitter

std::vector a un comportement étrange

    21 janvier 2024 à 13:41:33

    hello,

    Je rencontre un problème avec un vector. en effet ce dernier a un comportement très étrange que je ne comprends pas. voici le code en question:

    void patternsRecoAlignement::Corrector::__buildPatterns() {
    
    	for (int i = 0; i < this->sequence->size(); i++) {
    
    		this->stars->at(i) = *this->sequence->getStars(i);
    
    		patternsRecoAlignement::dataStructures::Pattern* p = nullptr;
    		
    		for (int j = 0; j < this->stars->at(i).size(); j++) {
    
    			std::vector<std::pair<float, float>>* closestStars = this->__findClosestStars(i, j);
    			std::vector<patternsRecoAlignement::dataStructures::Triangle>* triangles = this->__buildTriangles(closestStars);
    			
    			p = new patternsRecoAlignement::dataStructures::Pattern(triangles); 
    			this->patterns->at(i).push_back(*p); //ligne a problèmes... patterns est un vector<vector<Pattern>>*
    			
    
    			delete closestStars;
    
    		}
    		
    	}
    
    }

    quand i =0 et j = 0, tout ce passe bien :

    par contre, pour i =0, j =1 c'est le dramme:

    Pour je ne sais qu'elle raison, quand la fonction push_back est appelé, et l'object en [0] a été déréférencé. Du coup, je me retrouve avec une violation mémoir, pour j =2 

    _CONSTEXPR20 _Ty exchange(_Ty& _Val, _Other&& _New_val) noexcept( conjunction_v<is_nothrow_move_constructible<_Ty>, is_nothrow_assignable<_Ty&, _Other>>) { // assign _New_val to _Val, return previous _Val _Ty _Old_val = static_cast<_Ty&&>(_Val); _Val         = static_cast<_Other&&>(_New_val); return _Old_val; }

    la pile d'appelle: 

    Quelqu'un a une idée sur ce qu'il ce passe? 

    merci d'avance

    -
    Edité par spartan117du13 21 janvier 2024 à 13:50:16

    • Partager sur Facebook
    • Partager sur Twitter
      21 janvier 2024 à 17:47:51

      Ton code est tres suspicieux. En particulier ton usage des pointeurs. Je ne serais pas surpris que le problème ne vienne pas de vector et la ligne que tu as indiqué.

      Donne le code des structures que tu utilises et des fonctions (sequence, getStars, __findClosestStars, etc)

      A mon avis, vire tes pointeurs. Leur utilisation est étrange et on fait jamais de pointeur de vector. Et si tu veux réellement utiliser des pointeurs, utilise unique_ptr.

      Evite les noms qui commencent avec __ ou _X (majuscule), c'est réservé dans certains cas.

      Evite "this->" partout, c'est lourd a la lecture. Utilise les range for loop et auto pour alleger le code aussi.

      • Partager sur Facebook
      • Partager sur Twitter
        21 janvier 2024 à 19:17:41

        Ici n'a pas les sources qui permettraient de voir et encore moins de reproduire le problème, donc c'est difficile de dire pourquoi.

        Cependant on voit une tendance à utiliser explicitement des adresses et des déreférencements explicites (opérateur *).

        A tout hasard, un truc qui pose souvent problème avec ce genre de notions, c'est qu'un vecteur contient des données qui peuvent déménager quand on ajoute des éléments dans un vecteur (à cause de la réallocation du tableau dynamique sous-jacent au vecteur)

        Un exemple :  le programme ci-dessous ajoute 0,1,.... 999 dans un vecteur d'entiers. Et regarde si par hasard ça n'aurait pas fait changer l'adresse du premier élément (et des suivants évidemment) :

        #include <iostream>
        #include <vector>
        
        int main()
        {
            std::vector<int> vecteur;
            int *adresse_premier = nullptr;
        
            for (int i = 0; i < 1000; i++) {
                vecteur.push_back(i);
                if (adresse_premier != & vecteur[0]) {
                    std::cout << "déménagement ajout de " << i << std::endl;
                    adresse_premier = & vecteur[0];
                }
            }
        	return EXIT_SUCCESS;
        }
        

        Compilation et exécution

        $ make
        g++ -std=c++20 -Wall -Wextra -pedantic -Werror -Wno-unused -g    prog.cc   -o prog
        
        $ ./prog 
        déménagement ajout de 0
        déménagement ajout de 1
        déménagement ajout de 2
        déménagement ajout de 4
        déménagement ajout de 8
        déménagement ajout de 16
        déménagement ajout de 32
        déménagement ajout de 64
        déménagement ajout de 128
        déménagement ajout de 256
        déménagement ajout de 512

        Exercice : en déduire

        • le prochain ajout qui provoquera un déménagement
        • la stratégie de réallocation utilisée pour l'extension du tableau dynamique des vecteurs dans cette implémentation.

        Ici, peut être que findClosestStart retourne une adresse d'un truc qui déménage ensuite à cause d'un push_back quelque part, et donc que closestStar est un pointeur contenant une adresse devenue invalide. Ou p ?

        Aussi : autant que possible, déclarer les variables seulement au moment où on est capable de leur donner une valeur qui a un sens.  Et en général, avec le type auto si il fauit le job (déclarer explicitement un type, c'est indiquer au lecteur que le type auto ne convient pas, et il faudrait expliquer pourquoi).  Le pointeur p - si il doit exister - pourrait être déclaré dans la boucle

        auto p = new patternsRecoAlignement::dataStructures::Pattern(triangles); 



        -
        Edité par michelbillaud 21 janvier 2024 à 19:29:07

        • Partager sur Facebook
        • Partager sur Twitter
          21 janvier 2024 à 20:34:28

           Merci de vos réponses.

          gbdivers a écrit:

          Ton code est tres suspicieux. En particulier ton usage des pointeurs. Je ne serais pas surpris que le problème ne vienne pas de vector et la ligne que tu as indiqué.

          Donne le code des structures que tu utilises et des fonctions (sequence, getStars, __findClosestStars, etc)

          A mon avis, vire tes pointeurs. Leur utilisation est étrange et on fait jamais de pointeur de vector. Et si tu veux réellement utiliser des pointeurs, utilise unique_ptr.

          Evite les noms qui commencent avec __ ou _X (majuscule), c'est réservé dans certains cas.

          Evite "this->" partout, c'est lourd a la lecture. Utilise les range for loop et auto pour alleger le code aussi.

           je peux me passer des pointeurs et je veux bien abandonner leur utilisation. Cependant, si ce n'est pas le cas, le projet sur lequel je travaille est censé pouvoir traiter des images, trouver des étoiles et construire des motifs afin d'aligner automatiquement les images. Autrement dit, un vecteur peut être lourd. Dans le cas où la réponse est non, l'utilisation des pointeurs est une nécessité pour éviter les copies lors du passage d'arguments à une méthode.

          J'ai néanmoins fait un test rapide en transformant `vector<vector<pattern>>*` en `vector<vector<pattern>>`, mais le problème reste le même. Pour l'utilisation de `unique_ptr`, je suis d'accord, mais je préfère personnellement gérer la mémoire. C'est plus stimulant, et comme c'est un projet personnel, autant que ce soit formateur :D. L'utilisation de `this` peut paraître lourde, mais je la trouve personnellement plus claire : elle permet de savoir qui est membre de la classe et qui est simplement un objet de portée locale.

          Cela ne me dérange pas de partager le code des méthodes (d'ailleurs, le projet est totalement open source et je l'ai mis sur GitHub à l'adresse  antoinech13/AstroBase (github.com) ). Cependant, je ne pense vraiment pas que le problème puisse venir d'une autre partie du code. Le code que j'ai partagé ici est une version décomposée du code original. Cela me permet de placer des points d'arrêt un peu partout et de vérifier ce qui pose problème. D'ailleurs, on voit bien, sur les images dans mon premier message, que pour i=0 et j=0, le vecteur stocke bien en [0] un pattern de taille 5 (c'est ce qu'il est censé faire). Cependant, pour i=0 et j=1, ce pattern en [0] est de taille 0. C'est ça le problème que je ne comprends pas.

          michelbillaud a écrit:

          Ici n'a pas les sources qui permettraient de voir et encore moins de reproduire le problème, donc c'est difficile de dire pourquoi.

          Cependant on voit une tendance à utiliser explicitement des adresses et des déreférencements explicites (opérateur *).

          Un truc qui pose parfois avec ce genre de notions, c'est qu'un vecteur contient des données qui peuvent déménager quand on ajoute des éléments dans un vecteur (à caause de la réallocation du tableau dynamique sous-jacent au vecteur)

          Un exemple :  le programme ci-dessous ajoute 0,1,.... 999 dans un vecteur d'entiers. Et regarde si par hasard ça n'aurait pas fait changer l'adresse du premier élément (et des suivants évidemment) :

          #include <iostream>
          #include <vector>
          
          int main()
          {
              std::vector<int> vecteur;
              int *adresse_premier = nullptr;
          
              for (int i = 0; i < 1000; i++) {
                  vecteur.push_back(i);
                  if (adresse_premier != & vecteur[0]) {
                      std::cout << "déménagement ajout de " << i << std::endl;
                      adresse_premier = & vecteur[0];
                  }
              }
          	return EXIT_SUCCESS;
          }
          

          Compilation et exécution

          $ make
          g++ -std=c++20 -Wall -Wextra -pedantic -Werror -Wno-unused -g    prog.cc   -o prog
          
          $ ./prog 
          déménagement ajout de 0
          déménagement ajout de 1
          déménagement ajout de 2
          déménagement ajout de 4
          déménagement ajout de 8
          déménagement ajout de 16
          déménagement ajout de 32
          déménagement ajout de 64
          déménagement ajout de 128
          déménagement ajout de 256
          déménagement ajout de 512

          Exercice : en déduire

          • le prochain ajout qui provoquera un déménagement
          • la stratégie de réallocation utilisée pour l'extension du tableau dynamique des vecteurs dans cette implémentation.

          -
          Edité par michelbillaud il y a moins de 30s

          Cette petite expérience est intéressante, en effet. Cependant, le problème ne vient pas du fait que l'adresse mémoire de mes objets change, mais plutôt que, pour i=0 et j=0, le vecteur[0] stocke un objet de type "pattern" de taille 5, et que pour i=0 et j=1, le vecteur en question stocke deux objets, mais que vecteur[0] est maintenant un objet "pattern" de taille 0. C'est comme s'il avait détruit l'objet en position 0.

          Je comprends que c'est difficile à déboguer. Le problème est que c'est la première fois que cela m'arrive avec des vecteurs, et je ne sais pas si je pourrais créer un exemple simple reproduisant l'erreur. De plus, le projet utilise deux ou trois bibliothèques et peut être un peu compliqué à compiler. Comme mentionné précédemment, le code est disponible ici : antoinech13/AstroBase (github.com). Ma conviction est que cela ne soit pas d'une grande aide.

          Je vais essayer de reproduire l'erreur sur un exemple simple, mais je ne suis pas sûr d'y parvenir.

          Néanmoins, je partage le code des structures de données Pattern et Triangle. Il n'est pas impossible qu'il contienne quelque chose qui perturbe le comportement du vecteur.

          fichier .h:

          class Triangle {
          
          public:
          	Triangle();
          	Triangle(std::vector< std::pair<float, float>>* stars, float eps = 2);
          	Triangle(std::pair<float, float> *s1, std::pair<float, float>* s2, std::pair<float, float>* s3, float eps = 2);
          	~Triangle();
          
          	std::pair<float, float>* s1();
          	std::pair<float, float>* s2();
          	std::pair<float, float>* s3();
          	
          	std::pair<float, float>* v1();
          	std::pair<float, float>* v2();
          	std::pair<float, float>* v3();
          
          	float d1();
          	float d2();
          	float d3();
          
          	float getRotAngle(Triangle* t);
          
          	float distance(Triangle* t);
          
          	std::pair<float, float>* minus(Triangle* t);
          
          	void correctFromRot(float angle, std::pair<float, float>* center);
          
          	// surcharge d'opérateur
          
          	bool operator==(Triangle& t);
          
          
          private:
          	std::array<std::pair<float, float>, 3>* stars;
          	std::array<std::pair<float, float>, 3>* vectors = nullptr;
          	std::array<float, 3>* distances = nullptr;
          	float eps;
          
          	void __computeDistances();
          	void __computeVectors();
          
          
          };
          
          class Pattern {
          
          public:
          
          	Pattern(std::vector<Triangle>* triangles);
          	~Pattern();
          
          
          	int size();
          
          	float distance(Pattern* t);	
          	std::pair<float, float>* minus(Pattern* t);
          
          	float computeAngle(Pattern* t);
          
          	void correctFromRot(float angle, std::pair<float, float>* center);
          
          	// surcharge d'opérateur
          	bool operator==(Pattern& t);
          
          	
          
          private:
          	std::vector<Triangle>* triangles;
          
          };

          fichier .cpp

          #include "data_structures.h"
          
          patternsRecoAlignement::dataStructures::Triangle::Triangle()
          {
          }
          
          patternsRecoAlignement::dataStructures::Triangle::Triangle(std::vector<std::pair<float, float>>* stars, float eps) {
          	
          	if (stars->size() < 3 || stars->size() > 3) 
          		std::cout << "Error: not good number of stars to create triangles" << std::endl;
          	
          	this->stars = new std::array<std::pair<float, float> ,3>{ stars->at(0), stars->at(1), stars->at(2) };
          	this->__computeDistances();
          	this->__computeVectors();
          
          	this->eps = eps;
          }
          
          patternsRecoAlignement::dataStructures::Triangle::Triangle(std::pair<float, float>* s1, std::pair<float, float>* s2, std::pair<float, float>* s3, float eps)
          {
          
          	this->stars = new std::array< std::pair<float, float>, 3 >{*s1, *s2, *s3};
          	this->__computeDistances();
          	this->__computeVectors();
          
          	this->eps = eps;
          }
          
          patternsRecoAlignement::dataStructures::Triangle::~Triangle()
          {
          	
          	//delete this->stars;
          	//delete this->vectors;
          	//delete this->distances;
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::s1()
          {
          	return &this->stars->at(0);
          }
          
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::s2()
          {
          	return &this->stars->at(1);
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::s3()
          {
          	return &this->stars->at(2);
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::v1()
          {
          	return &this->vectors->at(0);
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::v2()
          {
          	return &this->vectors->at(1);
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::v3()
          {
          	return &this->vectors->at(2);
          }
          
          float patternsRecoAlignement::dataStructures::Triangle::d1()
          {
          	return this->distances->at(0);
          }
          
          float patternsRecoAlignement::dataStructures::Triangle::d2()
          {
          	return this->distances->at(1);
          }
          
          float patternsRecoAlignement::dataStructures::Triangle::d3()
          {
          	return this->distances->at(2);
          }
          
          bool patternsRecoAlignement::dataStructures::Triangle::operator==(Triangle& t)
          {
          	return std::abs( this->d1() - t.d1() ) <= this->eps && std::abs( this->d2() - t.d2() ) <= this->eps && std::abs( this->d3() - t.d3() ) <= this->eps;
          }
          
          void patternsRecoAlignement::dataStructures::Triangle::__computeDistances()
          {
          	if (this->distances == nullptr)
          		this->distances = new std::array<float, 3>();
          
          
          	this->distances->at(0) = patternsRecoAlignement::Utils::eucledianDistance(this->s2(), this->s1());
          	this->distances->at(1) = patternsRecoAlignement::Utils::eucledianDistance(this->s3(), this->s1());
          	this->distances->at(2) = patternsRecoAlignement::Utils::eucledianDistance(this->s3(), this->s2());
          }
          
          void patternsRecoAlignement::dataStructures::Triangle::__computeVectors()
          {
          	if (this->vectors == nullptr)
          		this->vectors = new std::array<std::pair<float, float>, 3>();
          
          	this->vectors->at(0) = *patternsRecoAlignement::Utils::buildVect(this->s1(), this->s2());
          	this->vectors->at(1) = *patternsRecoAlignement::Utils::buildVect(this->s1(), this->s3());
          	this->vectors->at(2) = *patternsRecoAlignement::Utils::buildVect(this->s2(), this->s3());
          }
          
          float patternsRecoAlignement::dataStructures::Triangle::getRotAngle(Triangle* t)
          {
          
          
          	float scal1 = this->v1()->first * t->v1()->first + this->v1()->second * t->v1()->second;
          	float scal2 = this->v2()->first * t->v2()->first + this->v2()->second * t->v2()->second;
          	float scal3 = this->v3()->first * t->v3()->first + this->v3()->second * t->v3()->second;
          
          
          	float cosAgl1 = scal1 / (this->d1() * t->d1());
          	float cosAgl2 = scal2 / (this->d2() * t->d2());
          	float cosAgl3 = scal3 / (this->d3() * t->d3());
          		
          	float angle1 = acos( cosAgl1 );
          	float angle2 = acos( cosAgl2 );
          	float angle3 = acos( cosAgl3 );
          
          	int sign1 = patternsRecoAlignement::Utils::sign(this->d1() * t->d1() * std::sin(angle1));
          	int sign2 = patternsRecoAlignement::Utils::sign(this->d1() * t->d1() * std::sin(angle1));
          	int sign3 = patternsRecoAlignement::Utils::sign(this->d1() * t->d1() * std::sin(angle1));
          
          
          	if (cosAgl1 > 1)
          		angle1 = 0;
          	else if(cosAgl1 < -1)
          		angle1 = M_PI;
          
          	if (cosAgl2 > 1)
          		angle2 = 0;
          	else if (cosAgl2 < -1)
          		angle2 = M_PI;
          
          	if (cosAgl3 > 1)
          		angle3 = 0;
          	else if (cosAgl3 < -1)
          		angle3 = M_PI;
          
          
          	if (sign1 == 0)
          		sign1 = 1;
          	if (sign2 == 0)
          		sign2 = 1;
          	if (sign3 == 0)
          		sign3 = 1;
          
          	int sign = (sign1 + sign2 + sign3 ) / 3 ;
          
          	return (-sign*angle1 + -sign*angle2 + -sign*angle3) / 3.0;
          }
          
          
          float patternsRecoAlignement::dataStructures::Triangle::distance(Triangle* t)
          {
          	float dist = 0;
          
          	dist += patternsRecoAlignement::Utils::eucledianDistance(this->s1(), t->s1());
          	dist += patternsRecoAlignement::Utils::eucledianDistance(this->s2(), t->s2());
          	dist += patternsRecoAlignement::Utils::eucledianDistance(this->s3(), t->s3());
          
          	return dist/3;
          }
          
          void patternsRecoAlignement::dataStructures::Triangle::correctFromRot(float angle, std::pair<float, float>* center)
          {
          	this->stars->at(0).first -= center->first;
          	this->stars->at(0).second -= center->second;
          	this->stars->at(1).first -= center->first;
          	this->stars->at(1).second -= center->second;
          	this->stars->at(2).first -= center->first;
          	this->stars->at(2).second -= center->second;
          
          
          	patternsRecoAlignement::Utils::rot(&this->stars->at(0), angle);
          	patternsRecoAlignement::Utils::rot(&this->stars->at(1), angle);
          	patternsRecoAlignement::Utils::rot(&this->stars->at(2), angle);
          
          	this->stars->at(0).first += center->first;
          	this->stars->at(0).second += center->second;
          	this->stars->at(1).first += center->first;
          	this->stars->at(1).second += center->second;
          	this->stars->at(2).first += center->first;
          	this->stars->at(2).second += center->second;
          
          
          
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Triangle::minus(Triangle* t)
          {
          	return new std::pair<float, float>(t->s1()->first - this->s1()->first, t->s1()->second - this->s1()->second);
          }
          
          
          patternsRecoAlignement::dataStructures::Pattern::Pattern(std::vector<Triangle>* triangles) : triangles(triangles)
          {
          
          }
          
          patternsRecoAlignement::dataStructures::Pattern::~Pattern()
          {
          	delete this->triangles;
          }
          
          int patternsRecoAlignement::dataStructures::Pattern::size()
          {
          	return this->triangles->size();
          }
          
          bool patternsRecoAlignement::dataStructures::Pattern::operator==(Pattern& t) 
          {
          	 if (this->size() != t.size())
          		return false;
          
          	 bool res = this->triangles->at(0) == t.triangles->at(0);
          	
          	 for(int i = 1; i < this->size(); i++)
          		 res = res && ( this->triangles->at(i) == t.triangles->at(i) );
          
          	return res;
          }
          
          float patternsRecoAlignement::dataStructures::Pattern::distance(Pattern* t)
          {
          	float dist = 0;
          
          	for (int i = 0; i < this->triangles->size(); i++)
          		dist += this->triangles->at(i).distance(&t->triangles->at(i));
          
          	return dist / this->triangles->size();
          }
          float patternsRecoAlignement::dataStructures::Pattern::computeAngle(Pattern* t)
          {
          	float angle = 0;
          
          	for (int i = 0; i < this->triangles->size(); i++)
          		angle += this->triangles->at(i).getRotAngle(&t->triangles->at(i));
          
          	return angle / this->triangles->size();
          }
          
          void patternsRecoAlignement::dataStructures::Pattern::correctFromRot(float angle, std::pair<float, float>* center)
          {
          	for (int i = 0; i < this->triangles->size(); i++)
          		this->triangles->at(i).correctFromRot(angle, center);
          }
          
          std::pair<float, float>* patternsRecoAlignement::dataStructures::Pattern::minus(Pattern* t)
          {
          	for(int i = 0; i < this->triangles->size(); i++)
          		return this->triangles->at(i).minus(&t->triangles->at(i));
          }








          -
          Edité par spartan117du13 21 janvier 2024 à 20:35:35

          • Partager sur Facebook
          • Partager sur Twitter
            21 janvier 2024 à 20:52:13

            Le lien vers ton GitHub ne marche pas. As tu mis le projet en public ?
            • Partager sur Facebook
            • Partager sur Twitter
              21 janvier 2024 à 21:04:46

              [utilisation de this-> pour savoir qui est membre de la classe]

              La solution habituelle (la plus courante en C++ ?) est d'utiliser un préfixe comme my_ ou m_ pour les données membres, ce qui les différencie clairement des paramètres des fonctions..

              C'est m_ comme membre, pas comme moche, encore que.

              Il y avait aussi _ tout court, en prefixe ou suffixe,  mais c'est plutôt déconseillé. Peu visible et en conflit avec autre usage de _

              [C'est comme si il avait détruit]

              Peut être que quand on ajoute dans un vecteur, et que ça provoque une réallocation, les éléments sont déménagés en appelant un constructeur (de copie ?) , et que celui-ci est défectueux ?

              -
              Edité par michelbillaud 21 janvier 2024 à 21:17:13

              • Partager sur Facebook
              • Partager sur Twitter
                21 janvier 2024 à 21:30:39

                Tu n'as pas donné le code des fonctions. Mais quand je vois ca :

                return &this->stars->at(0);

                Je pencherais pour le problème donné par michelbillaud : un pointeur qui devient invalide.

                spartan117du13 a écrit:

                l'utilisation des pointeurs est une nécessité pour éviter les copies lors du passage d'arguments à une méthode.

                Non, utilise des references (constantes de préférence).

                spartan117du13 a écrit:

                J'ai néanmoins fait un test rapide en transformant `vector<vector<pattern>>*` en `vector<vector<pattern>>`, mais le problème reste le même. 

                Ce n'est pas que ce code qui pose problème, mais a priori comment tu utilises en général des pointeurs.

                spartan117du13 a écrit:

                mais je préfère personnellement gérer la mémoire. 

                C'est une erreur, mais c'est ton choix.

                EDIT : tu es optimiste d'ouvrir une issue sur le GH de microsoft. C'est normalement fait pour rapporter des bugs, pas pour poser des questions de C++. Je pense qu'ils vont tiquer aussi sur les pointeurs de vector et ils vont probablement te répondre d'apprendre le C++ (s'ils répondent).

                -
                Edité par gbdivers 21 janvier 2024 à 21:33:52

                • Partager sur Facebook
                • Partager sur Twitter
                  21 janvier 2024 à 23:53:24

                  spartan117du13 a écrit:

                  mais je préfère personnellement gérer la mémoire.

                  C'est tout à votre honneur de vouloir gérer la mémoire, ce n'est pas du tout une mauvaise chose ! Mais en effet si c'est pour faire des new/delete à la main, je vous conseille vivement d'utiliser des smart pointers car quitte à faire quelque chose de moisi, autant que ça soit "un peu plus propre" et surtout standard, car si vous voulez travailler sur du C++ plus tard, vous ne verrez personne faire des new/delete dans du code métier (sauf ceux qui ne savent pas ce qu'ils font). D'une manière générale, si vous faites quelque chose qui consiste à faire exactement la même chose que ce que propose le C++, alors utilisez plutôt la fonctionnalité existante, le fait de faire les choses à la main c'est pour justement pouvoir faire mieux mais faire des new/delete ce n'est pas mieux du tout.

                  Je n'ai pas accès au code source donc je ne sais pas s'il y a moyen de gérer la mémoire de ce projet manuellement tout en proposant quelque chose de substantiellement mieux que ce qui serait fait classiquement. Bien entendu, s'il s'agissait juste de stocker quelques objets dans un vecteur, ça ne serait pas vraiment bénéfique de sortir l'arena (pour ceux qui savent de quoi je parle), il faut que le problème soit un minimum complexe pour commencer à en ressentir les bienfaits.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    22 janvier 2024 à 2:09:09

                    JadeSalina a écrit:

                    s'il y a moyen de gérer la mémoire de ce projet manuellement tout en proposant quelque chose de substantiellement mieux que ce qui serait fait classiquement. 

                    On fait d'abord un truc qui marche avant de faire un truc qui marche plus vite. Parce qu'aller plus vite quand ça marche pas, ça permet juste de faire un plus gros splatch contre le mur.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      22 janvier 2024 à 8:05:52

                      Sinon, pourquoi on ne parle pas du message (pile d'appel) qui dit que le crash se produit dans le destructeur ~Pattern ligne 209 ?

                      Ps: on pourrait pas profiter des namespaces pour raccourcir les définitions de fonctions avec noms à rallonge, genre a::b::c::d::mafonction() ?

                      -
                      Edité par michelbillaud 22 janvier 2024 à 8:11:08

                      • Partager sur Facebook
                      • Partager sur Twitter
                        22 janvier 2024 à 11:32:05

                        Manipuler toutes ces paires via des indirections va coûter une blinde -- et je ne parle même pas des temps requis pour les allocations et les libérations.

                        Garde tout dans les mêmes caches, et fais confiance au compilo pour être efficace pour passer et renvoyer des paires par valeurs -- enfin, surtout sur linux où il le fera en plus directement dans les registres.

                        Donc ouste **tous** tes pointeurs, et le code va très vite se simplifier et il ne restera plus que les éventuels problèmes d'invalidation. Éventuels, car je n'ai pas vérifié ce que mes VDD semblent avoir vu.

                        NB: le traitement d'image n'est pas exactement une activité critique, j'opte de fait pour la programmation offensive (assertions) plutôt que la défensive (std::vector::at). Tes performances s'en porteront mieux en plus.

                        -
                        Edité par lmghs 22 janvier 2024 à 13:57:55

                        • Partager sur Facebook
                        • Partager sur Twitter
                        C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                          22 janvier 2024 à 11:38:16

                          JadeSalina a écrit:

                          car si vous voulez travailler sur du C++ plus tard, vous ne verrez personne faire des new/delete dans du code métier (sauf ceux qui ne savent pas ce qu'ils font). 


                          Tu idéalises vraiment le monde professionnel, huhu ^^
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                            22 janvier 2024 à 12:56:31

                            Faudrait aussi 

                            • Déclarer des types pour les trucs usuels, genre coord2d au lieu de pair<double, double>
                            • Remplacer
                            • p1.first = p2.first;
                              p1.second = p2.second;
                              Par    p1 = p2; (en bref, définir et utiliser les abstractions qui correspondent au niveau du problème) 
                            • Utiliser des tableaux à 3 éléments plutôt que 3 données, et des boucles

                            Le dernier, ça éviterait les accidents de copier coller comme les lignes 126-128 (vu par hasard).

                            Mais avant ça, faire un beau diagramme de classes pour décider si un machin possède un truc, ou fait juste réference à un truc  qui est par ailleurs la propriété d'un bidule. C'est un préalable à la bonne utilisation des pointeurs (savoir qui a la responsabilité de faire les delete / choisir le type de smart pointer qui convient)

                            -
                            Edité par michelbillaud 22 janvier 2024 à 13:16:58

                            • Partager sur Facebook
                            • Partager sur Twitter
                              22 janvier 2024 à 19:04:45

                              Quelle chance, STL t'a répondu sur l'issue sur GH :)

                              Bon, pas de surprise, le pointeur sur le vector le fait tiquer. Et il pense aussi a un problème d'invalidation des pointeurs avec les push_back.

                              • Partager sur Facebook
                              • Partager sur Twitter
                                22 janvier 2024 à 22:09:59

                                Hello,

                                Wow, je n'aurais jamais pensé que cela provoquerait autant de réactions ^^". Merci en tout cas pour toutes vos réponses. J'ai finalement résolu le problème. La solution a été de changer les

                                array<std::pair<float, float>, 3>*

                                par des: 

                                array<std::pair<float, float>, 3>

                                (je parles des structure de données Triangle et Pattern)

                                Mais j'ai du mal à comprendre. Je saisis l'idée selon laquelle le vecteur va relocaliser la mémoire afin d'optimiser. Par conséquent, je m'attends effectivement à ce qu'un objet de type "Pattern" dans un vecteur de type "vector<Pattern>" change d'adresse. Cependant, je ne vois pas pourquoi les données internes à cet objet doivent également changer d'adresse, et pourquoi le fait de ne plus utiliser de pointeurs mais un objet en dur permet de résoudre ce problème.

                                Si je peux décrire cela de manière grossière, si je suis dans une maison (ma position dans le vecteur), que je souhaite envoyer une lettre à quelqu'un (l'adresse de cette personne qui est présente sur la lettre correspond donc à mes "array<pair, 3>*"). Si je déménage et que, par conséquent, je change d'adresse, je ne vois pas pourquoi le destinataire de la lettre, lui, change d'adresse.

                                D'autre part, même si je peux comprendre que parfois c'est un peu excessif d'écrire vector<int>* (et j'en ai très probablement abusé :D), je ne vois pas vraiment où est le problème. Certes, le vecteur gère la mémoire en interne et je n'ai pas besoin de m'en soucier, mais écrire vector<int> ou vector<int>* à la fin, dans la mémoire, il y aura de toute façon un vector<int> stocké qui gérera en interne des entiers. La seule différence est que moi je manipule une simple adresse plutôt qu'un objet qui peut être lourd.

                                Je ne peux malheureusement pas répondre à tous les commentaires, cependant je tiens à vous remercier pour les conseils apportés.

                                J'ai d'autres questions qui me viennent. Mais avant cela, il faut quand même que je précise certaines choses.

                                Je comprends l'idée d'éviter d'utiliser les pointeurs et de préférer, dans le cas où c'est nécessaire, l'utilisation des smartPtr. Surtout dans le monde professionnel où l'on cherche à développer vite et bien, et donc à ne pas perdre de temps à gérer d'éventuels problèmes de mémoire. Ma première question, qui est une vraie question, c'est pourquoi coder en C++? :D Je veux dire par là que de mon point de vue, l'intérêt est justement que le langage soit de bas niveau et qu'il permette d'être précis dans le comportement du code. Si la gestion de mémoire "fait peur" et qu'on lui préfère des outils qui gèrent à notre place (et encore une fois je comprends tout à fait dans le cas du monde professionnel), pourquoi ne pas plutôt coder en Java ou C#? Encore une fois, c'est une vraie question et pas une remarque.

                                Cela m'amène à un point qui, je pense, est important. Ce projet est un projet personnel et je me suis donné comme objectif d'utiliser les pointeurs de base de C++ et d'essayer d'optimiser au mieux à la fois le temps d'exécution et la mémoire par moi-même (ce qui conduit et conduira bien évidemment à du refactoring constant). Je peux comprendre que des professionnels puissent tiquer en voyant cela, mais cela me permet d'apprendre car c'est réellement ce qui me motive. Par exemple, je ne serais jamais tombé sur ce bug, je n'aurais jamais appris le fonctionnement profond des vecteurs. Alors que maintenant, j'ai commencé à lire le code des vecteurs pour essayer de comprendre comment c'est géré en interne. Aussi, j'apprends bien évidemment à gérer les fuites de mémoire et cela me permet de repenser mon code pour faire en sorte d'optimiser au mieux ma mémoire. Chose que je n'aurais probablement jamais faite si je n'utilisais pas les pointeurs justement (et oui, c'est fastidieux et ça me prend beaucoup de temps:D).

                                Je ne prétends pas écrire un code qui suive parfaitement la norme professionnelle, et cela m'amène à ma autre question. Je veux bien qu'on me fasse la réflexion sur le fait que ce n'est pas un code professionnel, mais je ne vois pas en quoi c'est mal d'utiliser les fonctionnalités de C++? Quand je regarde les cours de C++ donnés (même celui sur OpenClassroom), personne n'apprend le C++ "professionnel". Tous les cours apprennent l'utilisation des pointeurs standards et rares sont ceux qui ne feraient que mentionner les shared_ptr et unique_ptr. Encore une fois, dans une volonté d'apprendre, si vous avez des sources ou des cours pour apprendre le C++ "professionnel", je suis tout à fait preneur.

                                Donc voilà, en conclusion, si vous avez des conseils, des références ou autre pour améliorer mon C++, je suis tout à fait preneur et croyez bien que cela ne tombera pas dans l'oreille d'un sourd ;)

                                Merci beaucoup!

                                -
                                Edité par spartan117du13 22 janvier 2024 à 22:16:46

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  22 janvier 2024 à 23:26:58

                                  Un std::vector gère un espace mémoire en interne.
                                  A l'instanciation, il va allouer un certain espace.
                                  Lorsque tu ajoute des éléments, si la place vient à manquer, il va faloir trouver plus de place.
                                  Comme on ne peut augmenter la taille d'un espace mémoire, il n'y a pas 36 solutions:
                                  1) Allouer un nouvel espace mémoire plus grand.
                                  2) Deplacer les elements dans le nouvel espace.
                                  3) Detruire l'ancien espace.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    22 janvier 2024 à 23:58:03

                                    Deedolith a écrit:

                                    Un std::vector gère un espace mémoire en interne.
                                    A l'instanciation, il va allouer un certain espace.
                                    Lorsque tu ajoute des éléments, si la place vient à manquer, il va faloir trouver plus de place.
                                    Comme on ne peut augmenter la taille d'un espace mémoire, il n'y a pas 36 solutions:
                                    1) Allouer un nouvel espace mémoire plus grand.
                                    2) Deplacer les elements dans le nouvel espace.
                                    3) Detruire l'ancien espace.

                                    En effet, j'avais compris ce point. Ce qui me perturbe plutôt est le fait que si j'ai un vector<Pattern> et que Pattern utilise des pointeurs comme arguments, pourquoi les arguments internes de Pattern sont supprimés. Je comprends que les objets Pattern soient réalloués pour agrandir l'espace du vecteur, mais pourquoi en interne de Pattern, la mémoire est libérée alors que lorsque je remplace les pointeurs par les valeurs directes, le vecteur n'a aucun problème pour passer ces données.

                                    Au début, je pensais que le vecteur appelle simplement le destructeur de Pattern pour réallouer et que forcément, si dans mon destructeur je supprime les pointeurs, alors forcément, s'il passe au nouveau Pattern après réallocation les adresses qui ont été libérées plus tôt, ça pose problème. Cependant, mon destructeur de Pattern ne supprime pas les pointeurs. D'où mon interrogation sur ce qui se passe.

                                    D'ailleurs, je dis qu'il les supprime, mais en réalité, je n'en sais rien. Il pourrait aussi changer leurs adresses sans les supprimer (ce qui est pire). Je vais tester ça par curiosité pour voir si les adresses ont changé.

                                    -
                                    Edité par spartan117du13 22 janvier 2024 à 23:58:33

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      23 janvier 2024 à 0:08:20

                                      spartan117du13 a écrit:

                                      Cependant, je ne vois pas pourquoi les données internes à cet objet doivent également changer d'adresse, et pourquoi le fait de ne plus utiliser de pointeurs mais un objet en dur permet de résoudre ce problème.

                                      Sans ton code, on peut pas expliquer ce qui n'allait pas et pourquoi ca fonctionne maintenant.

                                      spartan117du13 a écrit:

                                      (l'adresse de cette personne qui est présente sur la lettre correspond donc à mes "array<pair, 3>*"). Si je déménage et que, par conséquent, je change d'adresse, je ne vois pas pourquoi le destinataire de la lettre, lui, change d'adresse.

                                      L'analogie est bancale, mais si tu envoie un pointeur, tu envoies ton adresse. Donc si tu déménages, c'est plus valide.

                                      spartan117du13 a écrit:

                                      D'autre part, même si je peux comprendre que parfois c'est un peu excessif d'écrire vector<int>* (et j'en ai très probablement abusé :D), je ne vois pas vraiment où est le problème. Certes, le vecteur gère la mémoire en interne et je n'ai pas besoin de m'en soucier, mais écrire vector<int> ou vector<int>* à la fin, dans la mémoire, il y aura de toute façon un vector<int> stocké qui gérera en interne des entiers. La seule différence est que moi je manipule une simple adresse plutôt qu'un objet qui peut être lourd.

                                      C'est juste une mauvaise pratique.

                                      spartan117du13 a écrit:

                                      Je comprends l'idée d'éviter d'utiliser les pointeurs et de préférer, dans le cas où c'est nécessaire, l'utilisation des smartPtr. Surtout dans le monde professionnel où l'on cherche à développer vite et bien, et donc à ne pas perdre de temps à gérer d'éventuels problèmes de mémoire.

                                      Quand tu apprends, ton temps est limité. Le temps que tu prends a apprendre quelque chose, c'est du temps que tu ne passe pas a apprendre autre chose.

                                      spartan117du13 a écrit:

                                      c'est pourquoi coder en C++? :D Je veux dire par là que de mon point de vue, l'intérêt est justement que le langage soit de bas niveau et qu'il permette d'être précis dans le comportement du code. Si la gestion de mémoire "fait peur" et qu'on lui préfère des outils qui gèrent à notre place (et encore une fois je comprends tout à fait dans le cas du monde professionnel), pourquoi ne pas plutôt coder en Java ou C#? Encore une fois, c'est une vraie question et pas une remarque.

                                      Il y a une grosse différence entre "coder en C++" et "apprendre le C++".

                                      Quand tu apprend, tu es obligé de suivre une démarche pédagogique, sinon tu risques de ne pas comprendre les choses. Cela impose souvent de voir les choses dans un certain ordre et apprendre une nouvelle chose que quand tu as un certain niveau de compréhension des prérequis. On voit dans tes codes que tu n'as pas certaines bases de compréhension de ce que tu utilises. Le problème n'est pas forcément d'utiliser des pointeurs, mais que cela bloque ou ralentisse ton apprentissage, en te focalisant sur des bugs triviaux plutôt que sur des choses importantes.

                                      Et même hors apprentissage, il y a une différence entre "permet d'utiliser des pointeurs" et "utiliser des pointeurs partout". L'intérêt du C++ n'est pas de pouvoir faire que du bas niveau ! C'est de pouvoir choisir quand on fait du bas niveau et quand on n'en fait pas. Et donc, la première étape est de savoir quand il faut faut faire ce type d'optimisation.

                                      spartan117du13 a écrit:

                                      je me suis donné comme objectif d'utiliser les pointeurs de base de C++

                                      A priori, c'est une erreur pédagogique d'apprendre les pointeurs maintenant, d'après ce que je vois de ton niveau...

                                      spartan117du13 a écrit:

                                      d'essayer d'optimiser au mieux à la fois le temps d'exécution et la mémoire par moi-même (ce qui conduit et conduira bien évidemment à du refactoring constant). 

                                      ...parce que apprendre les pointeurs va a l'encontre de ton objectif, justement (optimiser).

                                      Comme tu le dis, tu vas devoir refactoriser souvent. Donc la première chose à apprendre, c'est pas d'optimiser avec des pointeurs, mais de savoir refactoriser. Et faire du code qui est facile a refactoriser. Donc du code correctement conçue, facile a lire, facile a modifier, facile à detecter les erreurs, tester son code, etc.

                                      La seconde chose est de savoir comment optimiser. Tu crois que pour optimiser, il faut utiliser des pointeur, ce qui est faux. Les pertes de performances viennent en premier des choix de structures et d'algos, le respect des caches, ce genre de chose. En partant de cette idée préconçue, tu n'apprend pas a optimiser, tu apprends des détails syntaxiques des langages C/C++.

                                      Un autre point, c'est qu'il faut savoir quoi optimiser. Donc apprend a mesurer les performances d'un code, avoir un démarche logique de recherche de problèmes et de solutions. En partant sur un code directement avec des pointeurs, tu n'optimise pas correctement, parce que tu n'as aucun idée de ce qui est pertinent d'être optimisé ou pas.

                                      spartan117du13 a écrit:

                                      je n'aurais jamais appris le fonctionnement profond des vecteurs. 

                                      Tu ne connais pas le fonctionnement profond de std::vector. (EDIT : ta réponse a Deedolith  confirme que tu n'as pas compris le fonctionnement de std::vector). Tu en es très loin. Si tu veux comprendre le fonctionnement profond de std::vector, il faut lire la doc technique sur le sujet.

                                      spartan117du13 a écrit:

                                      pour faire en sorte d'optimiser au mieux ma mémoire. Chose que je n'aurais probablement jamais faite si je n'utilisais pas les pointeurs justement (et oui, c'est fastidieux et ça me prend beaucoup de temps:D).

                                      Ce qui n'est pas le cas. La correction que tu as proposé ne change pas grand chose a l'optimisation de la mémoire. Travailler sur ce bug ne t'a rien appris sur comment on optimise la mémoire. C'est juste un constat : tu pensais apprendre certaines choses en utilisant les pointeurs, mais au final, de ce qu'on voit, tu n'as pas appris ces choses en travaillant sur ce bug. Tu as appris des choses, mais pas ce que tu visais.

                                      spartan117du13 a écrit:

                                      mais je ne vois pas en quoi c'est mal d'utiliser les fonctionnalités de C++? 

                                      Il ne faut pas non plus apprendre un C++ "professionnel", mais il faut suivre une certaine démarche pédagogique logique. Le problème n'est pas que tu apprends un C++ non professionnel, mais qu'apprendre des choses de façon non logique peut ralentir ton apprentissage, potentiellement de plusieurs années.

                                      spartan117du13 a écrit:

                                      Quand je regarde les cours de C++ donnés (même celui sur OpenClassroom), personne n'apprend le C++ "professionnel". Tous les cours apprennent l'utilisation des pointeurs standards et rares sont ceux qui ne feraient que mentionner les shared_ptr et unique_ptr. 

                                      Oui, c'est un problème.

                                      Le C++ est vieux et la façon de l'apprendre aussi. Beaucoup de cours/livres et de profs sont vieux et donc enseignent comme ils ont appris il y a 30 ans. C'est ce que l'on appelle l'approche historique.

                                      Sauf que cette approche n'a plus de sens dans la majorité des cas (exception par exemple pour l'embarqué - et encore, c'est discutable). Parce que les outils, les besoins, les ordinateurs, tout à changé depuis. Avant, utiliser des pointeurs permettait de comprendre réellement comment fonctionne la mémoire d'un ordinateur, parce qu'il y avait un lien directe entre la gestion de la mémoire par un ordinateur et par le C. Mais c'est plus le cas depuis très longtemps et si on veut apprendre comment fonctionne un ordinateur, la mémoire et comment optimiser, apprendre les pointeurs en premier n'est plus du tout pertinent. Il faut apprendre en premier a avoir un code clair, maintenable, qu'on va pouvoir mesurer, de façon a optimiser correctement. La qualité et la sécurité du code est indispensable pour optimiser correctement.

                                      Regarde par exemple le cours sur Zeste de savoir (la version beta, pas celle en ligne)

                                      -
                                      Edité par gbdivers 23 janvier 2024 à 15:40:47

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        23 janvier 2024 à 0:13:54

                                        Quand on dit "les éléments d'un vecteur peuvent changer d'adresse" (Quand le vecteur est agrandi),  ça veut dire que le tableau dynamique qui contient les éléments du vecteur est réalloué (probablement ailleurs) avec une taille plus grande (scoop : le double).

                                        Dans une vie précédente, j'avais écrit  https://mbillaud.fr/docs/Conteneurs/conteneurs.html#conteneurs pour expliquer comment ça marche (en C)

                                        Et si on avait des pointeurs vers ces éléments, ils (les pointeurs) deviennent invalides après la réallocation.

                                        Un contournement possible : remplacer les pointeurs vers ces éléments par des indices (par rapport au vecteur des éléments).

                                        Sur un autre sujet : il faut employer les pointeurs intelligents tant que possible, mais j'ai l'impression qu'on ne peut malheureusement pas les comprendre correctement avant d'avoir saisi ce qu'est un bête pointeur tout cours. Ce qui pose le problème d'apprendre un truc (et donc de le pratiquer) pour devoir s'abstenir de l'utiliser ensuite.

                                        -
                                        Edité par michelbillaud 23 janvier 2024 à 0:27:17

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          23 janvier 2024 à 0:35:10

                                          michelbillaud a écrit:

                                          il faut employer les pointeurs intelligents tant que possible, mais j'ai l'impression qu'on ne peut malheureusement pas les comprendre correctement avant d'avoir saisi ce qu'est un bête pointeur tout cours. 

                                          Je suis pas d'accord. A mon sens, cela semble plus simple d'expliquer comme cela, parce que c'est comme ça qu'on a appris. Pas parce que c'est mieux pédagogiquement.

                                          -
                                          Edité par gbdivers 23 janvier 2024 à 8:48:17

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            23 janvier 2024 à 9:03:04

                                            Deedolith a écrit:

                                            Un std::vector gère un espace mémoire en interne.
                                            A l'instanciation, il va allouer un certain espace.
                                            Lorsque tu ajoute des éléments, si la place vient à manquer, il va faloir trouver plus de place.
                                            Comme on ne peut augmenter la taille d'un espace mémoire, il n'y a pas 36 solutions:
                                            1) Allouer un nouvel espace mémoire plus grand.
                                            2) Deplacer les elements dans le nouvel espace.
                                            3) Detruire l'ancien espace.

                                            Salut !

                                            Il me semble - mais à confirmer si c'est dans la norme ou pas - que quand tu instancies un vector, il n'y a pas d'allocation.

                                            La première allocation du vector sera faite si tu le construis avec une taille, ou que tu le resize (ou reserve), ou dès que tu push.

                                            Je m'appuie la dessus pour parfois avoir plusieurs vector dans une structure, potentiellement non tous remplis : ceux non remplis ne consomment que la mémoire statique interne, mais n'allouent pas. 

                                            A confirmer.

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                              23 janvier 2024 à 15:36:32

                                              Fvirtman a écrit:

                                              mais à confirmer si c'est dans la norme ou pas 

                                              De mémoire, la norme de définie pas la stratégie d'allocation. En pratique, je crois que ca se passe comme ça, mais c'est pas garantie.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                23 janvier 2024 à 17:52:36

                                                > En pratique, je crois que ca se passe comme ça,

                                                Un coup d'oeil au source de la bib stl pour gnu c++

                                                https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a01069_source.html

                                                Le constructeur sans paramètre

                                                00217       vector()
                                                00218       : _Base() { }
                                                00219 

                                                appelle le constructeur de _Vector_Base  (type renommé _Base ligne 187)

                                                qui appelle le constructeur

                                                00106       _Vector_base()
                                                00107       : _M_impl() { }
                                                00108 
                                                

                                                qui initialise _M_impl qui est un champ

                                                00145     public:
                                                00146       _Vector_impl _M_impl;
                                                
                                                
                                                

                                                au moyen de ce constructeur

                                                00082     _Vector_impl()
                                                00083     : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0)
                                                00084     { }

                                                qui met _M_start à 0 (aka nullptr). Donc pas d'allocation.

                                                Et _M_start, c'est le pointeur vers la zone allouée, ça se voit ici

                                                00112       _Vector_base(size_t __n)
                                                00113       : _M_impl()
                                                00114       {
                                                00115     this->_M_impl._M_start = this->_M_allocate(__n);
                                                00116     this->_M_impl._M_finish = this->_M_impl._M_start;
                                                00117     this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
                                                00118       }





                                                -
                                                Edité par michelbillaud 23 janvier 2024 à 17:53:29

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  24 janvier 2024 à 10:54:45

                                                  Bonjour,

                                                  Si on regarde la valeur de retour de 'capacity()' on peut aussi savoir si il y a eu allocation.:)

                                                  Sur www.cppreference.com en regard de la fonction membre capacity il y a ceci de noté:

                                                  "returns the number of elements that can be held in currently allocated storage"

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

                                                  std::vector a un comportement étrange

                                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                  • Editeur
                                                  • Markdown