Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

array bound forbidden after parenthesized type-id

57 réponses
Avatar
Lucas Levrel
Bonjour,

J'utilise des objets alloués dynamiquement comme suit :
double (*data)[3];
data=new double[t][3];

Maintenant, je voudrais en faire un tableau. J'essaye donc :

double (**tab)[3];
tab=new (double(*)[3])[n];
for(int i=0;i<n;i++) tab[i]=new double[t][3];

et le compilateur (g++) me donne l'erreur que j'ai mise en sujet.
Est-ce que le code suivant, qui compile sans erreur, est équivalent à ce
que je veux faire ?

typedef double(*data_type)[3];
data_type *tab;
tab=new data_type[n];
for...

Si oui, pourquoi le compilateur refuse-t-il le premier code et pas le
second ?

Merci d'avance.
--
LL

10 réponses

1 2 3 4 5
Avatar
espie
In article ,
Pascal J. Bourguignon wrote:
Faire des vecteurs de vecteurs pose des gros problèmes de gestion de
mémoire et de temps d'accès aux éléments.

Mieux vaut faire comme le je démontrais, et comme le font tous les
compilateurs de tous les autres languages qui eux supportent les
tableaux multidimensionnels, (ce n'est pas "rocket-science" pourtant),
une seule allocation, et un indexage direct.



Si on veut faire des grosses matrices et assimilees, en theorie, c'est
valarray qui sert a ca. Je ne sais plus ou ca en est, j'ai un vague
souvenir qu'il y avait des soucis (et des mises-a-jour en C++0x), mais
je pense qu'un wandering Gaby pourra nous en dire plus, c'est pas comme
si il n'etait pas responsable de l'implementation dans la libstdc++ de
gcc...
Avatar
Lucas Levrel
Le 22 juillet 2009, Pascal J. Bourguignon a écrit :

Fabien LE LEZ writes:
> std::vector<> répond à la demande. Il suffit de l'encapsuler dans une
> classe qui va bien :

Faire des vecteurs de vecteurs pose des gros problèmes de gestion de
mémoire et de temps d'accès aux éléments.



C'est pour ça qu'il ne le fait pas :-p

Mieux vaut faire comme le je démontrais



Ton code est un peu trop compliqué pour moi. Est-il facilement adaptable
pour des tableaux à D dimensions ?

--
LL
Avatar
Lucas Levrel
Le 22 juillet 2009, Fabien LE LEZ a écrit :

std::vector<> répond à la demande. Il suffit de l'encapsuler dans une
classe qui va bien :

template <class T> class TableauTailleFixe3D



Merci ! Et pour mon instruction d'écriture, je fais simplement
fileout.write((char*) &tab(i,0,0), 3*t*sizeof(double));
? (Je suppose que oui grâce aux méthodes operator() que tu as définies,
mais comme je ne connais presque rien au C++ je préfère demander !)

Par ailleurs, cette implémentation que tu proposes réveille une question
que j'avais posée sur fclc il y a un mois, et qui n'avait pas eu de
réponse (enfin, le fil a plein de messages mais pas précisément sur ladite
question !). Pour résumer : soient les deux méthodes suivantes pour
implémenter un tableau bidimensionnel dont les données n'ont pas besoin
d'être contiguës,

1)
double **tab;
tab=new (double *)[m];
for(row=0;row<m;row++) tab[row]=new double[n];
Puis accès à l'élément (i,j) par tab[i][j]

2)
double *tab;
tab=new double[m*n];
int index(int row,int col){return row*n+col;};
Puis accès à l'élément (i,j) par tab[index(i,j)]

Par la méthode 1, l'accès se fait par deux déréférencements successifs.
Par la méthode 2, il faut une multiplication, une addition, et un
déréférencement. Si l'on étend ces méthodes au cas à D dimensions, la
méthode 1 requiert D déréférencements, la méthode 2 (D-1) multiplications
et additions, et un déréférencement. Qu'est-ce qui est le plus rapide ?


--
LL
Avatar
pjb
Lucas Levrel writes:

Le 22 juillet 2009, Pascal J. Bourguignon a écrit :

Fabien LE LEZ writes:
> std::vector<> répond à la demande. Il suffit de l'encapsuler dans une
> classe qui va bien :

Faire des vecteurs de vecteurs pose des gros problèmes de gestion de
mémoire et de temps d'accès aux éléments.



C'est pour ça qu'il ne le fait pas :-p

Mieux vaut faire comme le je démontrais



Ton code est un peu trop compliqué pour moi. Est-il facilement adaptable
pour des tableaux à D dimensions ?



Oui:

size_t row_major_index(size_t rank,size_t* dimensions,size_t* indices){
size_t i;
size_t r=0;
if(0<rank){
assert((0<=indices[0])and(indices[0]<dimensions[0]));
r=indices[0];
for(i=1;i<rank;i++){
assert((0<=indices[i])and(indices[i]<dimensions[i]));
r=(r*dimensions[i])+indices[i];
}
}
return(r);
}

Mais si tu as un nombre de dimensions (un rang) fixe, il vaut mieux
utiliser une formule en-ligne;

size_t row_major_index_2(size_t d0,size_t d1,
size_t i,size_t j){
assert((0<=i)and(i<d0)and(0<=j)and(j<d1));
return(i*d1+j); }

size_t row_major_index_3(size_t d0,size_t d1,size_t d2,
size_t i,size_t j,size_t k){
assert((0<=i)and(i<d0)and(0<=j)and(j<d1)and(0<=k)and(k<d2));
return(((i*d1+j)*d2)+k); }

size_t row_major_index_4(size_t d0,size_t d1,size_t d2,size_t d3
size_t i,size_t j,size_t k,size_t l){
assert((0<=i)and(i<d0)and(0<=j)and(j<d1)and(0<=k)and(k<d2)and(0<=l)and(l<d3));
return((((i*d1+j)*d2)+k)*d3+l); }

...



--
__Pascal Bourguignon__
Avatar
pjb
Lucas Levrel writes:

Le 22 juillet 2009, Fabien LE LEZ a écrit :

std::vector<> répond à la demande. Il suffit de l'encapsuler dans une
classe qui va bien :

template <class T> class TableauTailleFixe3D



Merci ! Et pour mon instruction d'écriture, je fais simplement
fileout.write((char*) &tab(i,0,0), 3*t*sizeof(double));
? (Je suppose que oui grâce aux méthodes operator() que tu as définies,
mais comme je ne connais presque rien au C++ je préfère demander !)



Je n'ai montré qu'un squelette, c'est à compléter.
Pour les entrées/sorties, tout dépend du format que tu veux utiliser.


Par ailleurs, cette implémentation que tu proposes réveille une question
que j'avais posée sur fclc il y a un mois, et qui n'avait pas eu de
réponse (enfin, le fil a plein de messages mais pas précisément sur ladite
question !). Pour résumer : soient les deux méthodes suivantes pour
implémenter un tableau bidimensionnel dont les données n'ont pas besoin
d'être contiguës,

1)
double **tab;
tab=new (double *)[m];
for(row=0;row<m;row++) tab[row]=new double[n];
Puis accès à l'élément (i,j) par tab[i][j]

2)
double *tab;
tab=new double[m*n];
int index(int row,int col){return row*n+col;};
Puis accès à l'élément (i,j) par tab[index(i,j)]

Par la méthode 1, l'accès se fait par deux déréférencements successifs.
Par la méthode 2, il faut une multiplication, une addition, et un
déréférencement. Si l'on étend ces méthodes au cas à D dimensions, la
méthode 1 requiert D déréférencements, la méthode 2 (D-1) multiplications
et additions, et un déréférencement. Qu'est-ce qui est le plus rapide ?



La seconde option est et sera de plus en plus la plus rapide.
http://www.cs.virginia.edu/papers/Hitting_Memory_Wall-wulf94.pdf


--
__Pascal Bourguignon__
Avatar
Fabien LE LEZ
On Wed, 22 Jul 2009 14:41:00 +0200, (Pascal J.
Bourguignon):

Mais tu as parlé de std::vector, ce qui en français se dit "vecteur".



Où as-tu encore été pêcher ça ?
Avatar
Fabien LE LEZ
On Wed, 22 Jul 2009 15:42:12 +0200, Lucas Levrel
:

Merci ! Et pour mon instruction d'écriture, je fais simplement
fileout.write((char*) &tab(i,0,0), 3*t*sizeof(double));



La fonction write() ne doit pas modifier le tableau, donc le type est
"char const*", pas "char*".

Note par ailleurs que toutes les données sont contiguës en mémoire. Tu
peux donc écrire :

fileout.write (reinterpret_cast<char const*>(&tab(0,0,0)),
n*3*t*sizeof(double));


Qu'est-ce qui est le plus rapide ?



Faut mesurer. C'est la seule façon d'être sûr.
Avatar
Fabien LE LEZ
On Wed, 22 Jul 2009 14:41:00 +0200, (Pascal J.
Bourguignon):

Non.



Si. C'est du moins la méthode canonique.
Comme je l'ai dit précédemment, il est possible que tu aies une bonne
raison, dans des cas précis, de faire différemment. Dans ce cas, on
étudie la situation minutieusement pour trouver la solution adaptée.

(Note : je parle bien de C++, pas de Lisp.)
Avatar
pjb
Fabien LE LEZ writes:

On Wed, 22 Jul 2009 14:41:00 +0200, (Pascal J.
Bourguignon):

Non.



Si. C'est du moins la méthode canonique.



Oui, mais le canon des programmeurs C++...


Comme je l'ai dit précédemment, il est possible que tu aies une bonne
raison, dans des cas précis, de faire différemment. Dans ce cas, on
étudie la situation minutieusement pour trouver la solution adaptée.

(Note : je parle bien de C++, pas de Lisp.)



En fait, rien n'empêche de définir une classe (template) specifique
pour des tableaux multidimentionnel. C'est juste une question
d'imagination, mais il semble bien que les programmeurs C++ n'en soit
pas capables, et se ramênent toujours à des vecteurs de vecteurs
qu'ils ont appris à faire en C...


--
__Pascal Bourguignon__
Avatar
Lucas Levrel
Le 22 juillet 2009, Fabien LE LEZ a écrit :

La fonction write() ne doit pas modifier le tableau, donc le type est
"char const*", pas "char*".



Ah oui, merci.

Note par ailleurs que toutes les données sont contiguës en mémoire. Tu
peux donc écrire :

fileout.write (reinterpret_cast<char const*>(&tab(0,0,0)),
n*3*t*sizeof(double));



- Qu'est-ce que reinterpret_cast<> ? (Quelle différence par rapport au
cast « bête » ?)
- J'ai bien noté que c'est contigu, mais je n'écris pas toutes les
« lignes » au même endroit, c'est pour ça que je disais &tab(i,0,0)
- Au fait, dans cette classe que tu proposes, quel est l'avantage
d'utiliser un vector plutôt que T *data et
data=new T[taille1_*taille2_*taille3_] ?

--
LL
1 2 3 4 5