Dans un autre fils, j'ai posé un code proposant un schéma d'allocation de mémoire pour un type abstrait de donnée Matrix qui a suscité le débat sur le plan du respect des contraintes d'alignement (Version 3 ci-dessous). Je crée ici une nouvelle discussion pour ne pas polluer le thread initial. Si la version 1 du code ci-dessous est celle généralement proposée, la version 2 est probablement plus facile à gérer par un débutant (moins d'allocation, gestion des erreurs allégée). Du point de vue de la performance, pour des grosse matrices, y a-t-il un avantage à allouer la mémoire pour chaque ligne de la matrice comme dans la version 1, par rapport à une allocation en masse comme dans la version 2 (p.ex. moins de swap)? Ou inversemment?
Les trois versions proposées sont:
Version 1: (nlines + 2) allocations de mémoire:
Version 2: 3 allocations de mémoire:
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 struct Matrix { double **_data; size_t dim[2]; }; #define MATRIX_INIT {NULL, {0}} struct Matrix *m_matrix_new(size_t nlines, size_t ncols) { struct Matrix *self = NULL; if (nlines > 0 && ncols > 0) { /* Hop, on change les habitudes et on alloue tout en un bloc */ self = malloc(sizeof *self); if (self != NULL) { static const struct Matrix tmp = MATRIX_INIT; /* Initialisation de tous les champs de la structure a une valeur nulle */ *self = tmp; self->dim[0] = nlines; self->dim[1] = ncols; self->_data = malloc(nlines * sizeof *self->_data); if (self->_data != NULL) { size_t i; size_t j; int err = 0; for (i = 0; i < nlines && err == 0; i++) { self->_data[i] = malloc(ncols *sizeof *self->_data[i]); if (self->_data[i] == NULL) { /* Echec d'allocation: on fait le menage, on sort de la boucle et on renvoit la valeur NULL */ do { i--; free(self->_data[i]); } while (i > 0); free(self->_data); free(self), self = NULL; err = 1; } } if (err == 0) { /* Initialisation */ for (i = 0; i < nlines; i++) { for (j = 0; j < ncols; j++) { self->_data[i][j] = 0.0; } } } } else { /* Echec de l'allocation: on fait le menage et on renvoit la valeur NULL */ free(self), self = NULL; } } else { /* Echec de l'allocation de memoire pour self: rien a faire, on renvoit la valeur NULL. */ } } return self; } struct Matrix * m_matrix_delete(struct Matrix *self) { if (self != NULL) { size_t i; for (i = 0; i < self->dim[0]; i++) { free(self->_data[i]); } free(self->_data); free(self), self = NULL; } return self; }
Version 3: 1 allocation de mémoire:
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 struct Matrix { double **_data; size_t dim[2]; }; #define MATRIX_INIT {NULL, {0}} struct Matrix *m_matrix_new(size_t nlines, size_t ncols) { struct Matrix *self = NULL; if (nlines > 0 && ncols > 0) { /* Hop, on change les habitudes et on alloue tout en un bloc */ self = malloc(sizeof *self); if (self != NULL) { static const struct Matrix tmp = MATRIX_INIT; /* Initialisation de tous les champs de la structure a une valeur nulle */ *self = tmp; self->dim[0] = nlines; self->dim[1] = ncols; self->_data = malloc(nlines * sizeof *self->_data); if (self->_data != NULL) { self->_data[0] = malloc(nlines * ncols * sizeof *self->_data[0]); if (self->_data[0] != NULL) { int i; for (i = 1; i < nlines; i++) { self->_data[i] = self->_data[0] + i * ncols; } /* Initialization */ for (i = 0; i < nlines * ncols; i++) { self->_data[0][i] = 0.0; } } else { /* Echec de l'allocation de memoire: on fait le menage et on renvoit la valeur NULL */ free(self->_data); free(self), self = NULL; } } else { /* Echec de l'allocation: on fait le menage et on renvoit la valeur NULL */ free(self), self = NULL; } } else { /* Echec de l'allocation de memoire pour self: rien a faire, on renvoit la valeur NULL. */ } } return self; } struct Matrix * m_matrix_delete(struct Matrix *self) { if (self != NULL) { free(self->_data[0]); free(self->_data); free(self), self = NULL; } return self; }
Avec mes meilleures salutations
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 struct Matrix { double **_data; size_t dim[2]; }; #define MATRIX_INIT {NULL, {0}} struct Matrix *m_matrix_new(size_t nlines, size_t ncols) { struct Matrix *self = NULL; if (nlines > 0 && ncols > 0) { /* Hop, on change les habitudes et on alloue tout en un bloc */ self = malloc(sizeof *self + nlines * sizeof *self->_data + nlines * ncols * sizeof **self->_data); if (self != NULL) { size_t i, j; static const struct Matrix tmp = MATRIX_INIT; /* Initialisation de tous les champs de la structure a une valeur nulle */ *self = tmp; self->dim[0] = nlines; self->dim[1] = ncols; /* Mise en forme de l'objet pour que tout pointe ou il faut */ self->_data = (double **) (self + 1); self->_data[0] = (double *) (self->_data + nlines); for (i = (size_t) 1; i < nlines; i++) { self->_data[i] = self->_data[0] + i * ncols; } /* Initialisation des elements de la matrice */ for (i = (size_t) 0; i < nlines; i++) { for (j = (size_t) 0; j < ncols; j++) { self->_data[i][j] = 0.0; } } } } return self; } void m_matrix_delete(struct Matrix *self) { if (self != NULL) { free(self); } }
Thierry
Partager