Implementation d'une classe Matrix

Le
Boris Sargos
Salut à tous,

Bjarne Substroup dans son livre référence, suggère une implémentation d'une
classe Matrix qui utilise la classe slice. C'est donc ce que j'ai fait.
Seulement la fonction membre

Slice_iter Matrix::row(size_t i); // TRES
CONTRAIGNANT

qui mathématiquement retourne le ième vecteur rangée de la matrice, retourne
ici un objet Slice_iter, qui n'est qu'un itérateur sur un valarray. Il
serait souhaitable qu'une telle fonction retourne réellement un vecteur afin
de pouvoir manipuler la ième rangée de la matrice comme un vecteur, en
particulier, qu'il puisse bénéficier des opérations vectorielles (*, +,
;..). Or, je n'ai pas l'intention de développer ces opérateurs pour la
classe Slice_iter, car ce serait très maladroit.
Pourtant, il est nécessaire d'utiliser un tel artifice afin de ne pas
recopier inutilement les données (performance oblige) dans un valarray :

valarray<double> Matrix::row(size_t i); // MALADROIT

Alors, je réfléchis à une solution hybride : une classe Vector qui pourrait
contenir son itérateur :

class Vector {
public:
// Constructeur
Vector(uint size) { v = new valarray<double>(size); s = 0; }
Vector(valarray<double>* vv, slice ss) { v = vv; s = new
slice(ss); }
~Vector() { if(s == 0) delete v; }
// Acces aux éléments
double& operator[] (uint i) { return ref(i); }
private:
valarray<double>* v;
slice* s;
double& ref(uint i) const { if(s == 0) return (*v)[i]; return
(*v)[s->start()+i*s->stride()]; }
}


Je ne sais pas quoi penser de cette implémentation. Un Vector peut donc
avoir deux facettes, selon que son slice soit nul ou pas. C'est surtout le
destructeur qui pose un problème. Ce modèle me semble fragile et dangereux.

J'aimerais avoir votre avis là-dessus.

Merci de m'avoir lu.
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Gabriel Dos Reis
Le #734261
"Boris Sargos"
| Salut à tous,
|
| Bjarne Substroup dans son livre référence, suggère une implémentation d'une
^^^^^^^^^

Je crois que tu voulais dire Stroustrup.

| classe Matrix qui utilise la classe slice. C'est donc ce que j'ai fait.
| Seulement la fonction membre
|
| Slice_iter Matrix::row(size_t i); // TRES
| CONTRAIGNANT
|
| qui mathématiquement retourne le ième vecteur rangée de la matrice, retourne
| ici un objet Slice_iter, qui n'est qu'un itérateur sur un valarray. Il

La raison pour laquelle, il a choisi de retourner un Slice_iter est
expliquée page 673:

The Slice_iters are used to circumvent the ban on copying
slice_arrays. I couldn't return a slice_array:

slice_array<double> row(size_t i) { return (*v)[slize(i, d2, d1)]; } // error

so I returned an iterator containing a pointer to the valarray and
the slice itself instead of a slice_array.

Cette restriction de la norme est une erreur comme je l'ai expliquée
dans §2 de « Fixing Valarray for Real World Use » :

http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2000/n1246.ps

Le comité, à l'époque, n'avait pas accordé grand intérêt à la chose. Il
a fallu que Robert Klarer reprennent les mêmes arguments pour que l'erreur
soit enfin corrigée :

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#253


[ Digression : si tu utilises GCC, tu auras noté qu'à cause d'un bug
dans le compilateur qui ne vérifiait pas les contrôles d'accès
comme il faut, on pouvait retourner les xxx_array par valeur.
GCC-3.4.0 est plus stricte maintenant, et la restriction ci-haut a
aussi été enlevée dans l'implémentation qui vient avec ce
compilateur. ]

| serait souhaitable qu'une telle fonction retourne réellement un vecteur afin
| de pouvoir manipuler la ième rangée de la matrice comme un vecteur, en
| particulier, qu'il puisse bénéficier des opérations vectorielles (*, +,
| ;..). Or, je n'ai pas l'intention de développer ces opérateurs pour la
| classe Slice_iter, car ce serait très maladroit.
| Pourtant, il est nécessaire d'utiliser un tel artifice afin de ne pas
| recopier inutilement les données (performance oblige) dans un valarray :
|
| valarray<double> Matrix::row(size_t i); // MALADROIT
|
| Alors, je réfléchis à une solution hybride : une classe Vector qui pourrait
| contenir son itérateur :
|
| class Vector {
| public:
| // Constructeur
| Vector(uint size) { v = new valarray<double>(size); s = 0; }

Hmm, je ne comprends pas ceci.

| Vector(valarray<double>* vv, slice ss) { v = vv; s = new
| slice(ss); }
| ~Vector() { if(s == 0) delete v; }
| // Acces aux éléments
| double& operator[] (uint i) { return ref(i); }
| private:
| valarray<double>* v;
| slice* s;
| double& ref(uint i) const { if(s == 0) return (*v)[i]; return
| (*v)[s->start()+i*s->stride()]; }
| }
|
|
| Je ne sais pas quoi penser de cette implémentation. Un Vector peut donc

Je ne comprends pas trop où tu veux en venir avec cette
implémentation. Est-ce que tu peux essayer de remplacer Slice_iter par
slice_array et voir les problèmes de conception/implémentation que tu as ?

-- Gaby
Publicité
Poster une réponse
Anonyme