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
Fabien LE LEZ
On Tue, 21 Jul 2009 17:49:29 +0200, Lucas Levrel
:

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



Tu as une raison de vouloir faire ça, ou tu aimes juste les ennuis ?

Le type "tableau" en C++, c'est std::vector<>. On peut décider
d'utiliser autre chose, mais seulement après y avoir mûrement
réfléchi.
Avatar
James Kanze
On Jul 21, 5:49 pm, Lucas Levrel wrote:

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];



Pourquoi faire simple quand on peut faire compliquer, n'est
pas ? Comme dit Fabien, std::vector est ton ami.

Quant à l'erreur, il aurait été plus simple si tu avais indiqué
quelle ligne provoquait l'erreur, mais à jouer aux devinettes
(« but just a guess », an anglais -- je ne trouve rien de mieux
en français, à cette heure du soir) : la première expression new
me semble louche. La syntaxe de new ne permet que deux
variants (sans les placement et d'autres) :
new new-type-id
new ( type-id )
Or, new-type-id ne permet qu'une expression assez limitée des
types, sans parenthèses. C-à-d que ta ligne se parse :

tab = (new (double (*)[3])) [n] ;

Le [n] n'apppartient pas à l'expression new. Et bien que l'expression
à
droite de l'affectation est tout à fait légale, le type qu'il en
donne (le résultat d'avoir appliqué l'operateurr [] sur le
résultat de l'expression new) n'est pas compatible avec le type
à gauche de l'affectation.

Si tu y tiens,
tab=new (double((*[n])[3])) ;
doit faire l'affaire. Mais je n'aimerais pas !a avoir à
maintenir de tel code.

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...



L'effet est sans doute le même. Et c'est plus lisible aussi.
Mais encore loin de ce qu'on aurait avec std::vector.

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



Parce que le permier n'est pas légal, et le second si.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
pjb
Fabien LE LEZ writes:

On Tue, 21 Jul 2009 17:49:29 +0200, Lucas Levrel
:

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



Tu as une raison de vouloir faire ça, ou tu aimes juste les ennuis ?

Le type "tableau" en C++, c'est std::vector<>. On peut décider
d'utiliser autre chose, mais seulement après y avoir mûrement
réfléchi.



En fait, ici j'ai l'impression que Lucas veut non pas des vecteurs,
mais des tableaux multidimentionnel, ou peut être seulement des
matrices.



class InvalidRow : public std::exception { ... };
class InvalidColumn : public std::exception { ... };

template <class Element> Column {
Matrix<Element>& matrix;
size_t column;
public:
Column(Matrix<Element>& aMatrix,size_t aColumn)
:matrix(aMatrix),column(aColumn) {};
Element& operator[](size_t row){ return(matrix.at(column,row)); }
};

template <class Element> Matrix {
size_t width;
size_t height;
Element* data;
public:
Matrix(size_t aWidth,size_t aHeight)
:width(aWidth),height(aHeight) {
data=new Element[aWidth*aHeight];
}
virtual ~Matrix(){ delete data; };
Column<Element>& operator[](size_t column){
if((0<=column) and (column<width)){
return(Column<Element>(*this,column);
}else{
throw InvalidColumn(column,width);
}
};
Element& at(size_t column,size_t row){
if((0<=column) and (column<width)){
if((0<=row) and (row<height)){
return(this->data[column*width+row]);
}else{
throw InvalidRow(row,height);
}
}else{
throw InvalidColumn(column,width);
}
};
Matrix<Element>& operator=(Matrix<Element>& other) const { ... };
bool operator==(Matrix<Element>& other){ ... };
Matrix<Element>& operator+(Matrix<Element>& other){ ... };
Matrix<Element>& operator-(Matrix<Element>& other){ ... };
Matrix<Element>& operator*(Matrix<Element>& other){ ... };
Matrix<Element>& operator*(const Element& scalar){ ... };
...
};

--
__Pascal Bourguignon__
Avatar
Fabien LE LEZ
On Wed, 22 Jul 2009 10:47:13 +0200, (Pascal J.
Bourguignon):

En fait, ici j'ai l'impression que Lucas veut non pas des vecteurs,



Possible. Je n'ai jamais parlé de vecteurs.

mais des tableaux multidimentionnel, ou peut être seulement des
matrices.



Un tableau de T à une dimension s'écrit vector<T>.
Un tableau de T à deux dimensions s'écrit vector< vector<T> >.
Un tableau de T à trois dimensions s'écrit
vector< vector< vector<T> > >.
etc.

Une matrice au sens mathématique est généralement une encapsulation
d'un vector< vector<T> >.
Avatar
Lucas Levrel
Le 21 juillet 2009, James Kanze a écrit :

Quant à l'erreur, il aurait été plus simple si tu avais indiqué
quelle ligne provoquait l'erreur,



Ah oui, désolé ! C'est cette ligne qui coince :
tab=new (double(*)[3])[n];

C-à-d que ta ligne se parse :

tab = (new (double (*)[3])) [n] ;

Le [n] n'apppartient pas à l'expression new.



OK. Pour me fixer les idées, quand on fait :
toto = new double[n];
c'est bien parsé comme new (double[n]) et non pas (new double)[n] ?

Si tu y tiens,
tab=new (double((*[n])[3])) ;
doit faire l'affaire. Mais je n'aimerais pas !a avoir à
maintenir de tel code.



Effectivement. Ça crée bien un tableau de n objets de type double(*)[3] ?

Merci pour tes explications.
--
LL
Avatar
Lucas Levrel
Merci pour votre aide !

En fait je veux un tableau à 3 dimensions n*t*3, et comme n et t sont très
grands, je ne veux pas qu'il occupe beaucoup plus que n*t*3*64 bits. Sinon
j'aurais fait :
double ***tab;
tab=new (double **)[n];
for(int i=0;i<n;i++){
tab[i]=new (double *)[t];
for(int j=0;j<t;j++) tab[i][j]=new double[3];
}
mais (sauf erreur dans mes tests) new double[3] consomme 4*64 bits.

De plus, ça m'arrange que les doubles soient contigus par paquets de t*3,
pour faire une écriture non formatée comme :
file_out.write((char*)tab[i],t*3*sizeof(double));

Tout ça m'a conduit à l'idée de faire des new double[t][3] et un tableau
de n pointeurs vers ceux-ci.

Mais, si ça existe, je suis preneur d'une façon de faire plus lisible et
pas significativement plus gourmande en mémoire. Comme l'a deviné Pascal,
les dimensions n et t sont constantes.

--
LL
Avatar
Fabien LE LEZ
On Wed, 22 Jul 2009 13:17:10 +0200, Lucas Levrel :

En fait je veux un tableau à 3 dimensions n*t*3, et comme n et t sont très
grands, je ne veux pas qu'il occupe beaucoup plus que n*t*3*64 bits



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


template <class T> class TableauTailleFixe3D
{
public:
TableauTailleFixe3D (size_t taille1_,
size_t taille2_, size_t taille3_)
: taille2 (taille2_)
, taille3 (taille3_)
, data (taille1_ * taille2_ * taille3_)
{}

T& operator() (size_t pos1, size_t pos2, size_t pos3)
{
return data [Index (pos1, pos2, pos3)];
}

T const& operator() (size_t pos1, size_t pos2, size_t pos3) const
{
return data [Index (pos1, pos2, pos3)];
}

private:
size_t Index (size_t pos1, size_t pos2, size_t pos3) const
{ return (pos1 * taille2 + pos2) * taille3 + pos3; }

size_t taille2, taille3;
std::vector<T> data;
};



Initialisation :

typedef TableauTailleFixe3D <long long> Tableau;
Tableau tab (n, t, 3);

Pour modifier la case (17,36,2) :

tab (17, 36, 2)= 42;
Avatar
Fabien LE LEZ
>typedef TableauTailleFixe3D <long long> Tableau;



Remplacer "long long" par "double" dans ton cas.
Avatar
pjb
Fabien LE LEZ writes:

On Wed, 22 Jul 2009 10:47:13 +0200, (Pascal J.
Bourguignon):

En fait, ici j'ai l'impression que Lucas veut non pas des vecteurs,



Possible. Je n'ai jamais parlé de vecteurs.



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


mais des tableaux multidimentionnel, ou peut être seulement des
matrices.



Un tableau de T à une dimension s'écrit vector<T>.
Un tableau de T à deux dimensions s'écrit vector< vector<T> >.
Un tableau de T à trois dimensions s'écrit
vector< vector< vector<T> > >.



Non.


--
__Pascal Bourguignon__
Avatar
pjb
Fabien LE LEZ writes:

On Wed, 22 Jul 2009 13:17:10 +0200, Lucas Levrel :

En fait je veux un tableau à 3 dimensions n*t*3, et comme n et t sont très
grands, je ne veux pas qu'il occupe beaucoup plus que n*t*3*64 bits



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.

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.


--
__Pascal Bourguignon__
1 2 3 4 5