J'ai un programme que j'ai modifié pour extraire des données.
Récemment, j'ai effectué une autre extraction de données et utilisé une solution de contournement faute de temps.
Maintenant, j'essaie de découvrir quel était le problème, car j'ai du temps libre.
Ci-dessous, il y a une fonction Act () qui est une fonction membre de la classe Mat, et elle forme une nouvelle matrice avec des données modifiées valeurs. Le Mat a un pointeur vers un tampon contenant des données réelles. J'ai trouvé qu'après la fonction Act () qui renvoie une matrice, la fonction 'operator =' est appelée. (il n'y avait pas de fonction 'operator =' donc je l'ai ajoutée. Peut-être que la valeur par défaut '= operator' était utilisée. Avec ou sans ma fonction 'operator =' ajoutée, cela ne produit pas la sortie finale à droite) Voici la partie de '=' qui renvoie les données (type Mat). (c'est un code c ++ mais je viens d'utiliser printf car ça marche quand même)
d0_out = d0_out.Act(NN_CELL::AT_TANH);
ope =, res val = 12199b0, src val = c07680, ligne = 128, col = 128
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd
3be0 bbfc bbf5 3bf8 3af0 bbf6 bbef b29f bbaf 3bfd
Ce '3be0 bbfc bbf5 ...' est le bon modèle.
La partie appelante ressemble à ceci.
XXX
Mais après l'affectation, vu de la fonction principale, les données sont bizarres (à l'intérieur de l'opérateur =, la copie semble avoir été faite correctement, mais à l'extérieur, ce n'est pas le cas).
MLP Layer 0 exécuté.
40de c2e2 c1eb 425e 3d4a c21b c187 b2b8 bfce 4358
Comme vous pouvez le voir, les données sont fausses.
La seule façon de produire une sortie correcte consiste à utiliser un nouvel objet et à lui attribuer le résultat de la fonction Act ().
NN_CELL::Mat<T> d0_out1 = d0_out.Act(NN_CELL::AT_TANH); // tmp work-around
Ensuite, d0_out1 (nouvel objet) contient le droit data (3be0 bbfc bbf5 ..), au lieu de l'original
printf("calling activation..\n");
d0_out = d0_out.Act(NN_CELL::AT_TANH);
std::cout << "MLP Layer 0 executed." << std::endl;
for(int i=0;i<10;i++){
printf("%04x ",((half_float::half *)d0_out.val_)[i].data_);
}
printf("\n");
Quel est le problème avec le code d'origine?
3 Réponses :
operator = devrait modifier * ceci, ne pas créer un nouvel objet temporel X, copier les données reçues vers X puis retourner X. Vous avez créé un objet temporel mais les données de la classe qui exécute operator = n'ont pas été modifiées!
Essayez ce code:
template<typename T>
Mat<T> Mat<T>::operator = (const Mat<T>& rhs)
{
int num_bytes = sizeof(T) * rhs.row_ * rhs.col_;
printf("ope = , res val = %x, src val = %x, row = %d, col = %d\n", this->val_, rhs.val_, rhs.row_, rhs.col_);
for(int i=0;i<10;i++){
printf("%04x ",((half_float::half *)rhs.val_)[i].data_);
}
printf("\n");
memcpy(this->val_, rhs.val_, num_bytes);
for(int i=0;i<10;i++){
printf("%04x ",((half_float::half *)this->val_)[i].data_);
}
printf("\n");
return *this;
}
Merci! c'est aussi la réponse, mais j'ai vu l'autre et je l'ai choisie en premier, désolé. (et l'autre m'a donné une autre explication). :)
a = a.Act () ne fonctionne pas, car vous avez mal implémenté operator = . Le operator = par défaut ne fonctionne pas dans ce cas car vous avez un pointeur dans votre classe, et lorsque le temporaire renvoyé par Act () est détruit, il invalide probablement le pointeur .
operator = est appelé, car vous avez écrit = dans votre code. Lorsque vous utilisez "tmp work-around", vous créez un nouvel objet, qui n'appelle pas operator = mais le constructeur de copie. Cela semble fonctionner.
Quant à la manière d'implémenter correctement operator = : l'opérateur d'affectation doit modifier l'objet existant, au lieu d'en renvoyer un nouveau.
Par exemple:
struct A {
int row_, col_;
float *val_;
A& operator=(const A& rhs) {
if (this != &rhs) {
const int num_bytes = sizeof(float) * rhs.row_ * rhs.col_;
row_ = rhs.row_;
col_ = rhs.col_;
memcpy(val_, rhs.val_, num_bytes);
}
return *this;
}
};
Wow, ça marche. Je ne savais pas que operator = devrait renvoyer * this . :). et je me rends compte que si j'utilise 'a =', le operator = pour a est utilisé et je dois y implémenter la deep copy . Merci des tonnes!
Comme les commentaires s'affichent correctement, l ' opérateur d'affectation est destiné un objet déjà existant. Vous en créez un nouveau et vous le renvoyez.
Essayez quelque chose comme ceci:
template<typename T>
Mat<T>& Mat<T>::operator = (const Mat<T>& rhs)
{
row_ = rhs.row_;
col_ = rhs.col_;
delete val_;
val_ = new T[row_*col_];
int num_bytes = sizeof(T) * rhs.row_ * rhs.col_;
printf("ope = , res val = %x, src val = %x, row = %d, col = %d\n", val_, rhs.val_, rhs.row_, rhs.col_);
for(int i=0;i<10;i++){
printf("%04x ",((half_float::half *)rhs.val_)[i].data_);
}
printf("\n");
memcpy(val_, rhs.val_, num_bytes);
for(int i=0;i<10;i++){
printf("%04x ",((half_float::half *)val_)[i].data_);
}
printf("\n");
return *this;
}
L'affectation est censée modifier
* ceci, pas créer un nouvel objet. Le code qui produit la sortie correcte n'est pas une affectation mais une initialisation. (Et vous devez lire sur "la règle de trois".) Tout cela est couvert dans livres décents .... ce qui me fait penser que c'est une implémentation avec l'idiome de copie et d'échange qui a oublié le "swap".
Pensez également à utiliser un idiome de copie et d'échange au lieu de
operator =manuscrit@molbdnilo peut-être que je ne suis pas au courant de quelque chose d'important. Je veux garder la fonction Act () telle quelle (pour retourner un nouvel objet), alors je ne peux pas faire 'a = a.Act ()' pour remplacer a? et pourquoi «= opérateur» a-t-il été appelé?
@ChanKim Je ne suis pas sûr de ce que vous vous demandez. Si vous avez surchargé l'opérateur,
a = a.Act ()est traduit ena.operator = (a.Act ()). (Notez que la valeur de retour n'est pas utilisée.)