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 :

Stack overflow à cause d'un vecteur d'objets relativement gros


Sujet :

C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut Stack overflow à cause d'un vecteur d'objets relativement gros
    Bonjour à tous,

    J'écris un programme en C++ pour un élève. Cela consiste à programmer un automate cellulaire qui mime la propagation d'un feu. En gros on a un gros tableau qu'on fait évoluer selon la règle suivante : si une cellule du tableau brûle au temps t, elle contamine ses voisines avec la probabilité p. J'ai besoin de conserver tous les temps intermédiaires afin qu'il puisse analyser la dynamique de propagation. J'ai écris le code suivant, qui fonctionne pour de petits tableaux (50x50) mais pas pour des gros (stack overflow)...

    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
     
    #include <iostream>
    #include <cmath>
    #include <vector>
    #include <array>
    #include <cstdlib>
     
    using namespace std;
     
    const int N = 501;
     
    class Cell{
    	int state;
    	int burning;
    	public:
    		void sets(int s){
    			state = s;
    		}
    		int gets(){
    			return state;
    		}
    		void setburning(int b){
    			burning = b;
    		}
    		int getburning(){
    			return burning;
    		}
    		Cell(){
    			state = 0;
    			burning = 0;
    		}
    		Cell(int s, int b){
    			state = s;
    			burning = b;
    		}
    		Cell operator= (Cell C){
    			int s = C.gets();
    			int b = C.getburning();
    			return Cell(s,b);
    		}
    };
     
    typedef  array<array<Cell,N+2>,N+2> Cells;
     
    int BurningNeighbors(Cells CA, int i, int j){
    	int Burn;
    	Burn = CA[i+1][j-1].getburning()+CA[i+1][j].getburning()+CA[i+1][j+1].getburning()+
    		CA[i][j-1].getburning()+CA[i][j+1].getburning()+CA[i-1][j-1].getburning()
    		+CA[i-1][j].getburning()+CA[i-1][j+1].getburning();
    	return Burn;
    }
     
    Cells evol(Cells CA, double p){
    	Cells CA2 = CA;
    	for (int i = 1; i < N+1; i++){
    		for (int j = 1; j < N+1; j++){
    			if (CA[i][j].gets() == 1){
    				CA2[i][j].sets(2);
    			}
    			else if (CA[i][j].gets() == 2){
    				CA2[i][j].sets(3);
    				CA2[i][j].setburning(0);
    			}
    			else if (CA[i][j].gets() == 0) {				
    				int Burn = BurningNeighbors(CA,i,j);
    				if (Burn > 0){		
    					double Guess = (double) (rand() % 1000)/1000.;
    					if (Guess < 1-pow(1-p,Burn)) {
    						//cout << "Guess: " << Guess << "; 1-(1-p)^Burn: " << 1-pow(1-p,Burn) << endl;
    						CA2[i][j].sets(1);
    						CA2[i][j].setburning(1);
    					}
    				}
    			}
    		}
    	}	
    	return CA2;
    }
     
    int isBurning(Cells CA){
    	for (int i = 1; i < N+1; i++){
    		for (int j = 1; j < N+1; j++){
    			if (CA[i][j].getburning() == 1){
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
     
    int main()
    {
    	// Creation of Cells vector
     
    	cerr << "Beginning " << endl;
     
    	double P = 0.2;
     
    	vector<Cells> *CAs = new vector<Cells>();
     
    	// Initialisation
    	cout << endl << "Initialisation" << endl << endl;
     
    	static Cells CA;
     
    	for (int j = 0; j < N+2; j++){
    		CA[0][j].sets(3);
    		CA[N+1][j].sets(3);
    	}
    	for (int i = 0; i < N+2; i++){
    		CA[i][0].sets(3);
    		CA[i][N+1].sets(3);
    	}
    	CA[floor(N/2)+1][floor(N/2)+1].sets(1); 
    	CA[floor(N/2)+1][floor(N/2)+1].setburning(1); 	
    	CAs->push_back(CA);
    	int T = 0;
    	while (isBurning(CAs->at(CAs->size()-1))){
    		T++;
    		cout << endl << "time step:" << T << endl << endl;
    		CAs->push_back(evol(CAs->at(CAs->size()-1),P));
    	}
     
    	return 0; 
    }
    Je pense que le problème se situe dans la déclaration de CAs (qui contient l'état du tableau pour chaque pas de temps), mais je n'en suis pas certain, j'ai donc mis une version simplifiée du code.

    N est la taille du tableau de cellules;
    P est la probabilité que le feu soit transmis d'une cellule à une de ses voisines;
    evol est la fonction qui prend le tableau au temps t et rend le tableau au temps t+1;
    isBurning rend 1 s'il y a des cellules qui brûlent dans le tableau, 0 sinon;
    BurningNeighbors calcule le nombre de voisins d'une cellule qui brûlent, la fonction étant appelée par evol;
    CAs contient tous les états du tableau, de son initialisation à l'extinction du feu.

    La question est probablement triviale pour un habitué du C++, soyez indulgents s'il vous plaît je n'ai commencé ce langage que très récemment

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Chaque Cells 503 * 503 * {2 ints}, que ca correspond a priori à 250000 * 8 octets soit 2 Mo, ce qui est déjà énorme.

    Ca ne peut pas marcher, a cause des fonctions:
    Cells evol(Cells CA, double p) reçoit une copie de son arguments lorsqu'elle est appelée. Et cette copie est faite dans la pile.


    Passe par des références.
    evol(Cells const& CA, double p)

    Mieux crée une classe Simulation adaptée (regarde la faq sur les matrices: pourquoi et comment)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Tout d'abord, merci pour ton aide

    J'ai modifié evol de la manière que tu m'as conseillée, j'ai eu cette erreur à la compilation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    CA_so.cpp: In function 'Cells evol(const Cells&, double)':
    CA_so.cpp:57:22: error: passing 'const value_type {aka const Cell}' as 'this' argument of 'int Cell::gets()' discards qualifiers [-fpermissive]
        if (CA[i][j].gets() == 1){
                          ^
    CA_so.cpp:60:27: error: passing 'const value_type {aka const Cell}' as 'this' argument of 'int Cell::gets()' discards qualifiers [-fpermissive]
        else if (CA[i][j].gets() == 2){
                               ^
    CA_so.cpp:64:27: error: passing 'const value_type {aka const Cell}' as 'this' argument of 'int Cell::gets()' discards qualifiers [-fpermissive]
        else if (CA[i][j].gets() == 0) {
    Je pense qu'il faut modifier gets() et getburning() dans la classe Cell, donc j'ai modifié le code ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int gets() const{
    			return state;
    		}
    int getburning() const{
    			return burning;
    		}
    J'avoue, avec un grand desarroi, avoir rajouté des const un peu partout jusqu'à compilation ^^'. Je pense que mettre un const à cet endroit spécifie au compilateur que ni state ni burning ne seront modifiés par les fonctions gets() et geotburning().

    J'ai rajouté des const& à BurningNeighbors et isBurning pour éviter la même erreur que tout à l'heure, j'ai maintenant une nouvelle erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    time step:255
     
     
    time step:256
     
    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
     
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information.
    Une idée ?

    Bon appétit :=)

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Cette erreur, c'est le "out of memory" du tas. En gros, un new qui n'arrive pas à allouer ton un objet. Je pense que c'est dû à ton vecteur de Cells, qui a besoin de faire des allocations de "N*2MO consécutifs" quand il s'agrandit... Essaie plutôt avec une std::list, qui devrait allouer objet par objet.

    Edit: Regarde aussi si tu ne peux pas écrire tous ces temps dans des fichiers pour libérer la RAM.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    C'est étrange, j'ai 32Go de RAM, normalement ça devrait passer non ? 256*2Mo ce n'est pas si grand...
    Je vais essayer avec une list, je vous dirai.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Quel OS?
    La plupart des compilos sous Windows sont encore en "32 bits par défaut", donc à moins de compiler ton programme pour x64, tu seras limité à 2GO d'espace d'adressage par processus.
    J'ignore s'il y a ce genre de limitations sous les unixoïdes 64 bits.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Je suis sous Windows 8.1, j'ai g++ 4.8.1. Si je compile avec le flag -m64 j'ai cette erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    CA_so.cpp:1:0: sorry, unimplemented: 64-bit mode not compiled in
     #include <iostream>
     ^
    Il est fort possible que j'utilise un mauvais compilateur du coup...

    J'ai regardé un peu comment fonctionnent les std::list, ça m'a l'air assez complexe pour accéder à un élément... std::vector alloue la mémoire différemment ?

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Bonjour,
    Une matrice 500x500 d'un objet qui fait quelques bits ce n'est rien du tout. Par exemple, je viens juste de compiler et exécuter le code suivant:
    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
    #include <iostream>
    #include <vector>
     
    struct Cell
    {
    	Cell() :is_burning(false), temperature(0) {}
    	bool is_burning;
    	int temperature;
    };
     
    class CellMatrix
    {
    public:
     
    	CellMatrix(int width, int height)
    		: buffer_(std::vector<Cell>(width*height))
    		, width_(width)
    		, height_(height)
    	{}	
     
    	size_t Width() const 	{ return width_; }
    	size_t Height() const 	{ return height_; }
    	size_t Size() const 	{ return buffer_.size(); }
     
    	const Cell &	operator () (size_t i, size_t j) const	{ return buffer_[i + j * width_]; }
    	Cell &		operator () (size_t i, size_t j)	{ return buffer_[i + j * width_]; }
     
    private:
    	CellMatrix(const CellMatrix&){} // make sure that the matrix won't be copied
    private:
    	std::vector<Cell> buffer_;
    	size_t width_, height_;
    };
     
    int main()
    {
    	CellMatrix matrix(5000, 5000);
     
    	std::cout << std::endl << std::endl << "ok" << std::endl;
    	getchar();
    }
    Ca fonctionne, en debug et en 32 bits. L'allocation (5000x5000) et la destruction prennent 3 ou 4 secondes, mais ça fonctionne. Le problème est donc ailleurs.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    @r0d:
    5000*5000, c'est juste 25 millions (x8 = 200MO).
    Le problème ici, c'est le vecteur de gros objets, de longueur croissante.

    @chalulu: La problématique pour ton conteneur est simple: As-tu besoin d'un accès arbitraire aux éléments (autre que le premier et le dernier) par index, ou bien un parcours de la liste est-il suffisant?

    Si tu as besoin d'un accès aléatoire, alors du auras besoin du vecteur. et il faudra trouver quelque chose de plus sioux (fichier, vecteur de pointeurs, etc.). Sinon, la std::list suffit.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Je viens d'essayer en couplant ce code avec MATLAB, à l'aide de mex qui utilise les compilateurs de Visual Studio. Le compilateur que j'utilisait avant était g++ de MinGW.
    Ca marche sans problème, c'est un peu lent avec des tableaux de 500x500 mais ça fonctionne sans faire planter MATLAB.
    Je pense que le problème se situe effectivement dans la capacité du compilateur à gérer les grosses données, possiblement à cause du fait qu'il soit fait pour les plateformes 64-bits. Je vais télécharger MinGW-w64 pour voir.

  11. #11
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Le problème ici, c'est le vecteur de gros objets, de longueur croissante.
    Anéfé, je viens de capter.
    J'ai l'impression que le problème vient de la boucle du main: il y a un push_back mais pas de sleep() => le tableau grossi à la vitesse de la lumière. Si le problème est bien là, alors utiliser une list ne changera (presque) rien. Pour info, quelle est la valeur de T lorsque ça plante?

    note: une recommandation se cache dans le code de mon précédent message; il vaut mieux utiliser un tableau de 1 dimension (1 vector de taille m*n) que 2 vectors (1 de taille m et 1 de taille n).
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  12. #12
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    @medinoc
    Je vais avoir besoin d'un accès à chaque élément ensuite, le but du programme étant de copier CAs dans un tableau ensuite pour pouvoir le passer à MATLAB. Ici je n'ai posté qu'une version simplifiée, sans interface avec MATLAB (histoire de ne pas compliquer encore plus le code que je poste ^^)
    @r0d
    Je ne connaissais pas sleep(), je vais regarder ce que c'est. Le code bug à T = 256, ce qui est louche effectivement. Faire du malloc() ne résoudrait-il pas le problème ? (un collègue vient de me suggérer ça)

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Qu'appelles-tu "faire du malloc()" et en quoi penses-tu que c'est différent, côté consommation et contiguïté mémoire, de ce qu'une std::list (une liste chaînée) ferait?

    PS:
    Regarde ta boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	while (isBurning(CAs->at(CAs->size()-1))){
    		T++;
    		cout << endl << "time step:" << T << endl << endl;
    		CAs->push_back(evol(CAs->at(CAs->size()-1),P));
    	}
    Les seuls CAs qu'elle utilise, c'est le dernier de la liste et celui que ta boucle ajoute à la fin (en clair, CAN et CAN-1). Les autres, ton code n'en a pas besoin pour l'instant, donc tu pourrais les archiver dans un ou plusieurs fichiers pour libérer leur place en RAM.

    PPS: CAs->at(CAs->size()-1) peut être simplement remplaçé par CAs->back(), qui marche aussi bien sur les vecteurs que les listes.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    sleep() c'est plus un concept: laisser "dormir" le programme entre chaque itération sinon ça pose plusieurs problèmes.
    Mais visiblement le problème n'est pas là non plus (256 c'est pas beaucoup), étant assumé que tu as fait les modifications proposées par leternel (passage par référence).
    Donc je ne sais pas :/
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  15. #15
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    @medinoc
    Je pensais utiliser malloc pour allouer la mémoire à chaque push_back. Il est possible que ça soit fait directement en fait, donc je ne sais pas si c'est très utile. Je t'avoue que j'ai un peu peur de me lancer dans l'écriture de fichiers, je n'en ai jamais fait et je ne sais pas si mex va digérer ce genre de trucs...
    @r0d
    J'ai bien fait les modifications recommandées, je vais reposter le code pour que ce soit plus clair et qu'on sache tous où on en est :
    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
     
    #include <iostream>
    #include <cmath>
    #include <vector>
    #include <array>
    #include <cstdlib>
     
    using namespace std;
     
    const int N = 501;
     
    class Cell{
    	int state;
    	int burning;
    	public:
    		void sets(int s){
    			state = s;
    		}
    		int gets() const{
    			return state;
    		}
    		void setburning(int b){
    			burning = b;
    		}
    		int getburning() const{
    			return burning;
    		}
    		Cell(){
    			state = 0;
    			burning = 0;
    		}
    		Cell(int s, int b){
    			state = s;
    			burning = b;
    		}
    		Cell operator= (Cell C){
    			int s = C.gets();
    			int b = C.getburning();
    			return Cell(s,b);
    		}
    };
     
    typedef  array<array<Cell,N+2>,N+2> Cells;
     
    int BurningNeighbors(Cells const& CA, int i, int j){
    	int Burn;
    	Burn = CA[i+1][j-1].getburning()+CA[i+1][j].getburning()+CA[i+1][j+1].getburning()+
    		CA[i][j-1].getburning()+CA[i][j+1].getburning()+CA[i-1][j-1].getburning()
    		+CA[i-1][j].getburning()+CA[i-1][j+1].getburning();
    	return Burn;
    }
     
    Cells evol(Cells const& CA, double p){
    	Cells CA2 = CA;
    	for (int i = 1; i < N+1; i++){
    		for (int j = 1; j < N+1; j++){
    			if (CA[i][j].gets() == 1){
    				CA2[i][j].sets(2);
    			}
    			else if (CA[i][j].gets() == 2){
    				CA2[i][j].sets(3);
    				CA2[i][j].setburning(0);
    			}
    			else if (CA[i][j].gets() == 0) {				
    				int Burn = BurningNeighbors(CA,i,j);
    				if (Burn > 0){		
    					double Guess = (double) (rand() % 1000)/1000.;
    					if (Guess < 1-pow(1-p,Burn)) {
    						//cout << "Guess: " << Guess << "; 1-(1-p)^Burn: " << 1-pow(1-p,Burn) << endl;
    						CA2[i][j].sets(1);
    						CA2[i][j].setburning(1);
    					}
    				}
    			}
    		}
    	}	
    	return CA2;
    }
     
    int isBurning(Cells const& CA){
    	for (int i = 1; i < N+1; i++){
    		for (int j = 1; j < N+1; j++){
    			if (CA[i][j].getburning() == 1){
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
     
    int main()
    {
    	// Creation of Cells vector
     
    	cerr << "Beginning " << endl;
     
    	double P = 0.2;
     
    	vector<Cells> *CAs = new vector<Cells>();
     
    	// Initialisation
    	cout << endl << "Initialisation" << endl << endl;
     
    	static Cells CA;
     
    	for (int j = 0; j < N+2; j++){
    		CA[0][j].sets(3);
    		CA[N+1][j].sets(3);
    	}
    	for (int i = 0; i < N+2; i++){
    		CA[i][0].sets(3);
    		CA[i][N+1].sets(3);
    	}
    	CA[floor(N/2)+1][floor(N/2)+1].sets(1); 
    	CA[floor(N/2)+1][floor(N/2)+1].setburning(1); 	
    	CAs->push_back(CA);
    	int T = 0;
    	while (isBurning(CAs->back())){
    		T++;
    		cout << endl << "time step:" << T << endl << endl;
    		CAs->push_back(evol(CAs->back(),P));
    	}
     
    	return 0; 
    }
    Je pense vraiment que le problème vient de comment le tas est géré par ma version de g++. En utilisant mex, qui lui utilise le compilateur de Visual Studio 2013, il n'y a pas de problème: le programme tourne et va jusqu'à T = 494.

  16. #16
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Normalement, si tu utilises une std::list au lieu d'un std::vector, la std::list allouera la mémoire pour chaque élément à chaque push_back(), évitant le problème de "tout réallouer d'un coup" du std::vector.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  17. #17
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    J'ai remplacé le std::vector par une std::list et effectivement le programme va jusqu'au bout pour N = 501. Il s'arrête ici à T = 495.
    En fait les vector allouent un certain espace mémoire qui quand il en passe d'être dépassé est déplacé d'un seul coup ? Et la list marche autrement c'est ça ?

    Il va par contre falloir que je me soucie un peu de comment accéder aux éléments de la list...

    Edit : par contre je viens d'essayer pour N = 1001 et cette fois le programme ne tourne plus du tout. Il ne rend pas les cout/cerr et semble bugger quand evol est appelée dans main().
    Le passage par référence était censé prévenir ces stack overflow intempestifs non ? J'ai peut-être mal compris ce que ça faisait...

  18. #18
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par chalulu Voir le message
    J'ai remplacé le std::vector par une std::list et effectivement le programme va jusqu'au bout pour N = 501. Il s'arrête ici à T = 495.
    En fait les vector allouent un certain espace mémoire qui quand il en passe d'être dépassé est déplacé d'un seul coup ? Et la list marche autrement c'est ça ?
    C'est ça, mais le vector est encore pire: Quand son espace mémoire est en passe d'être dépassé, il alloue un nouvel espace mémoire plus grand, copie (ou en C++11, move) le contenu de l'ancien vers le nouveau, puis désalloue l'ancien.
    Ce qui fait qu'il te faut deux fois plus de mémoire disponible à ce moment-là.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  19. #19
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Je ne comprend pas tout, mais je viens de travailler sur le dernier code que tu as posté, et j'ai quelques remarques qui pourraient aider à améliorer le code:

    Passer un paramètre de fonction par référence sert juste à éviter une copie de ce paramètre. En général, ça ne fais pas de différence, mais là, puisqu'il s'agit de gros objets, c'est extrêmement important.

    En informatique, nous avons des ressources limitées. Ici, la ressource qui pose problème c'est la mémoire. Afin de prévenir le problème des ressources disponibles, on fait en sorte de travailler dans des ensembles finis (ou au pire, dont on sait de façon sure qu'ils ne grandiront pas trop). Dans ton cas, à chaque itération de ta boucle (celle du main), tu ajoutes un gros tableau à un gros tableau. Donc, ça ne peut pas bien finir. Deux solutions: soit tu détermines dès le début une taille maximum à ton tableau final, soit tu fais en sorte de ne pas ajouter des gros tableaux à chaque itération.

    pas besoin d'allouer CAs sur le tas => remplacer vector<Cells> *CAs = new vector<Cells>(); par: vector<Cells> CAs;

    c'est un détail, mais tu n'as pas besoin de déclarer ton tableau CA comme static.

    en C et en C++, on commence les boucles à 0 (pas à 1, cf. les fonctions evol et isBurning). Je ne vais pas faire un long discours, mais je te conseille fortement de prendre cette habitude.

    Bref, à mon avis, c'est l'algorithme qui ne va pas. Il faut soit que tu fixe dès le début la taille du tableau final, soit que tu fasse en sorte d'ajouter un petit nombre de Cell à chaque itération. Mais même ce deuxième choix me parait difficile à implémenter correctement, car inévitablement, au bout d'un moment il n'y aura plus de mémoire.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  20. #20
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Service public

    Informations forums :
    Inscription : Juillet 2014
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Très bien, je retravaillerai ce code plus tard, en tous cas merci à tous pour votre aide
    En pratique maintenant je peux faire marcher ce code avec N = 501, ce qui n'est déjà pas si mauvais.
    J'étais surpris de ne pas pouvoir faire plus car j'ai l'habitude de travailler avec de très grosses données sans problème sous MATLAB... Il faut croire que les choses sont plus délicates en C++

Discussions similaires

  1. Réponses: 3
    Dernier message: 01/12/2009, 21h19
  2. Stack OverFlow
    Par Goundy dans le forum Langage
    Réponses: 2
    Dernier message: 24/12/2005, 21h35
  3. Problème de stack overflow
    Par heider dans le forum Langage
    Réponses: 13
    Dernier message: 22/09/2005, 19h50
  4. [MFC] Manipuler un vecteur d'objets
    Par Yellowmat dans le forum MFC
    Réponses: 4
    Dernier message: 13/07/2005, 14h37
  5. Stack overflow
    Par portu dans le forum Langage
    Réponses: 3
    Dernier message: 26/11/2003, 15h16

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