Comme le titre l'indique, j'ai besoin de créer un très gros tableau à deux dimensions. Seulement, une fois mon programme lancé, il crash. Après avoir googlé pendant des heures, j'ai bien compris que mon tableau ne peux pas prendre plus de mémoire que celle qui lui est allouée. Ainsi, une fois que la taille de mon tableau dépasse [300][300] = environ 224 Mb, tout crash! J'ai essayé avec des vectors, et avec les tableaux à la sauce c. ([1][2]...) La seule manière, il me semble, c'est de faire de l'allocation dynamique pour mon tableau. Mais je n'ai trouvé aucune manière de déclarer dynamiquement mon tableau, que ce soit en vector ou en C-style. Quelqu'un saurait-il comment faire, et ensuite m'indiquer comment accéder a chaque élement de mon tableau 2D?
Avec vector tu n'a pas besoin de faire d'allocation manuelle. Il est facilement resizable.
std::vector< int > vect; /* vect est un "tableau" qui ne contient rien*/
vect.push_back(5) /* contient maintenant un élément: 5
vect.push_back(18) /* contient deux éléments: 5 et 18
Pas de vector de vector. C'est bordélique au possible et c'est désoptimisé (au sens : ce n'est même pas que c'est pas optimisé, c'est carrément contre productif).
Ksass`Peuk, quel est le sizeof d'un multi_array de 1000 * 1000 de int ?
Je ne sais pas comment c'est instancié, et je n'ai pas le compilo sous la main la, mais est ce que c'est tout alloué sur la pile ? (si typiquement il y a un T[X][X] dans la classe), ou alors il y a une indirection et une allocation en interne qui fait que les données sont allouées sur le tas ?
Car si tes données sont allouées sur la pile, tu auras le même soucis.
Essaie, pour voir, un multiarray de 1000*1000 de int.
128 octets sur le la pile, c'est pas grand chose (enfin pas trop), ça prouve que beaucoup est alloué sur le tas par la suite. Car 1 million de int, c'est 4 Mo dans pas mal de cas.
@fvirtman si tu parle d'un boost::multi_array, les données sont probablement stockées directement sur le tas, sauf éventuellement optimisation sur les petits tableaux (un peu comme les small strings optimizations qui switchent (static/dynamic) si la taille de la chaine dépasse un une valeur arbitraire en dessous de laquelle l'allocation dynamique n'est clairement pas rentable, mais pas trop élevée non plus pour limiter l'overhead à un niveau raisonnable). Après sur un std::array linéarisé, je ne sais pas, un boost::array est une encapsulation d'un simple tableau C donc 1000*1000 * sizeof(T), il est probable que c'est pareil pour un std::array, mais je t'avouerai que je n'ai jamais été regardé (pour boost::array je sais, je m'en suis inspiré pour implémenter un truc dans le même genre pour une plateforme sur laquelle boost n'est pas utilisable sans de grosses modifications, et qui offre un support du standard C++98 disons... approximatif). Quoi qu'il en soit, si j'ai du 1000*1000 avec taille connue à l'avance, l'overhead d'un vector sera negligeable, et lui sera sur le tas, donc je vais utiliser un vector. Mon implémentation bricolée du boost::array, ne compile pas si N*sizeof(T) > 4ko, j'ai 64 ko de pile, donc pas de blagues.
Parce que ton truc ne respect pas le RAII en C++ ! Si une exception survient pendant ton for les allocations faites précédemment sont perdus et ne sont pas libérés !
Ce n'est pas bon parce que ce code n'est pas correct. Au moindre problème entre l'allocation de deux lignes et il va fuir comme pas possible.
Le code correct est le suivant: http://cpp.developpez.com/faq/cpp/?page=Gestion-dynamique-de-la-memoire#Comment-allouer-dynamiquement-un-tableau-a-plusieurs-dimensions
Après c'est sûr que quand on code au pays magique où les erreurs n'existent pas ... on peut se contenter de code crado. Je sais que c'est comme ça que sont écrits la plupart des cours de C (désolé, on est trolldi), mais ce n'est pas comme ça que les bons cours de C++ sont écrits.
Bref, si c'est pour un exo. Au choix : la double alloc (qui n'est pas très efficace en temps CPU) et qui demande de faire attention pour les échecs d'alloc. Ou la simple alloc où tout est linéarisé. Après, il y a les solutions identiques mais avec des vecteurs au lieu d'alloc à la main (cela permet d'expérimenter The Rule of Big Three et The Rule of Big Two -- voire 0 avec des vecteurs).
Si c'est pour du vrai code qui rentrera en production, il existe des COTS/FOSS & cie prêt à l'emploi et qui feront très bien le boulot. boost.multi_array pour des tableaux dynamiques quelconques, Eigen pour de l'algèbre linéaire, ...
Bah, avec la méthode de AlienX13, que j'aime bien d'ailleurs, il suffit d'une condition :
tab = new int*[h];
tab2 = new int[h * w];
if(tab && tab2){
for(int i = 0; i < h; i++){
tab[i] = tab2 + i*w;
}
}else{
//ERREUR!
}
//liberation
delete[] tab;
delete[] tab2;
En terme de rapidité les vecteurs sont beaucoup plus lent, surtout pour la création et il y a un "bound" test à chaque accès. C'est bien beau suivre les nouvelles normes, mais ça ne va être compatible que sur les compilateurs récents.
Et puis entre nous que tu ais un gentil message d'erreur te disant que tu manque de mémoire ou que ton application plante, ça change pas grand chose, pour les chances que ça arrive.
- Edité par Maeiky 18 juillet 2014 à 19:05:47
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
De plus, la condition ne sert à rien, contrairement à malloc, new ne renvoi pas zéro si l'allocation échoue mais lance une exception. Donc dans ton code, si la deuxième allocation échoue -> fuite (et je parle pas de tout ce qu'il peut y avoir entre l'allocation et la libération)...
J'ai ça comme résultat. L'algo, allouer deux dimensions et set de valeur tab[i][j] = i * j.
Create vector push_back Result : 61 ms
Create vector reserve + push_back Result : 28 ms
Create vector: std::vector<std::vector<int>> vec(nXLoop, std::vector<int>(nYLoop)); Result : 15 ms
Create boost multi_array Result : 18 ms
Create MatVector: std::vector<T> m_vec Result : 8 ms
Create MatSmartPtr: std::unique_ptr<T[]> m_vec Result : 5 ms
Create MatPtr: T* m_vec Result : 3 ms
Create pointer Result : 4 ms
vector push_back, vector push_back + reserve et create pointer sont les versions de Maeiky.
Les Mat* sont des classes que j'ai créé (tableau unidimensionnel acces i * width + j). Donc le mieu c'est de créer sa propre classe avec un pointeur nu et de respecter le RAII?
As-tu activé l'optimisation -o2 dans tes 2 test? Bizarre comme résultat.
C'est un vieux post je croyais avoir posté la différence entre les array normal et les vector ... mais j'ai déjà fais les tests quelque part, les vecteurs était toujours plus lent.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Si tu as des meilleurs résultats avec malloc qu'avec vector, c'est juste une mauvaise utilisation de vector ... Pour les types simples tu es aussi rapide, pour les types complexes tu as de bonnes chances d'être bien plus rapide avec vector. La différence c'est que vector est générique.
L'as-tu au moins essayé? J'ai retrouvé un de mes tests, le vector est exactement 2.5 fois plus lent, pour la création c'est 90 fois plus lent :
#include <iostream>
#include <vector>
#include <iterator>
#include <sys/timeb.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int nXLoop = 8000;
int nYLoop = nXLoop; //Must be same for both test
struct timeb start;
struct timeb end;
double time;
void endTimer(){
ftime(&end);
time = end.time-start.time;
time *= 1000;
time += end.millitm-start.millitm;
time /= 1000;
}
int main()
{
int nData;
///////////////////////////
////// Creation /////////
///////////////////////////
cout << endl <<" CREATE " << endl << endl;
cout << "Create vector" << endl;
ftime(&start);
vector< vector<int> > vec;
//vec.reserve(nXLoop);
for (int i = 0; i < nYLoop; i++) {
vector<int> row; // Create an empty row
//row.reserve(nYLoop);
for (int j = 0; j < nXLoop; j++) {
row.push_back(i * j); // Add an element (column) to the row
}
vec.push_back(row); // Add the row to the main vector
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "Create array with new" << endl;
ftime(&start);
int** aNew(new int*[nYLoop]);
for (int i = 0; i < nYLoop; i++){
aNew[i] = new int[nXLoop];
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "Create array with malloc" << endl;
ftime(&start);
int** aMalloc;
aMalloc = (int**) malloc(nYLoop*sizeof(int*));
for (int i = 0; i < nYLoop; i++){
aMalloc[i] = (int*) malloc(nXLoop*sizeof(int));
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
/////////////////////////////////////////
////////////////Write/////////////////////
/////////////////////////////////////////
cout << endl <<" WRITE " << endl << endl;
cout << "Vector write " << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
vec[y][x] = x*y;
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayNew write" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
aNew[y][x] = x*y;
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayMalloc write" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
aMalloc[y][x] = x*y;
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
/////////////////////////////////////////
////////////////Read/////////////////////
/////////////////////////////////////////
cout << endl <<" READ " << endl << endl;
cout << "Vector read " << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
nData = vec[y][x];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayNew read" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
nData = aNew[y][x];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayMalloc read" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
nData = aMalloc[y][x];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
/////////////////////////////////////////
////////////////Both/////////////////////
/////////////////////////////////////////
cout << endl <<" BOTH " << endl << endl;
cout << "Vector both " << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
vec[y][x] = vec[x][y];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayNew both" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
aNew[y][x] = aNew[x][y];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
cout << "ArrayMalloc both" << endl;
ftime(&start);
for (int y = 0; y < nYLoop; y++) {
for (int x = 0; x < nXLoop; x++) {
aMalloc[y][x] = aMalloc[x][y];
}
}
endTimer();
cout << "Result : "<< time << endl;
cout << endl;
}
//Ouptut
CREATE
Create vector
Result : 1.254
Create array with new
Result : 0.013
Create array with malloc
Result : 0.012
WRITE
Vector write
Result : 0.527
ArrayNew write
Result : 0.211
ArrayMalloc write
Result : 0.206
READ
Vector read
Result : 0.478
ArrayNew read
Result : 0.17
ArrayMalloc read
Result : 0.172
BOTH
Vector both
Result : 1.499
ArrayNew both
Result : 0.806
ArrayMalloc both
Result : 0.803
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.