IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Problème avec le passage par référence et la pile


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 274
    Par défaut Problème avec le passage par référence et la pile
    Bonjour à tous,

    Je vous montre d'abord le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
       std::vector<cv::Mat> tabMat;
     
      cv::Mat img(cv::Size(1,1), CV_8U);
      img.at<uint8_t>(0, 0) = 5;
     
      {
        cv::Mat imgClone;
        img.copyTo(imgClone);
        tabMat.push_back(imgClone);
      }
     
      std::cout << static_cast<int>(tabMat.at(0).at<uint8_t>(0, 0)) << std::endl;
      std::cout << static_cast<int>(img.at<uint8_t>(0, 0)) << std::endl;
    comme vous le voyez je créée dans un scope un objet imgClone, puis je l'insère dans mon vector, le problème c'est qu'en faisant ça j'appelle le constructeur de cv::Mat et le passage se fait par référence. Ce qui me gene c'est que la variable imgClone va être libérée en mémoire dans la pile à la sortie du scope et donc lorsque je ferai tabMat.at(0).at<uint8_t>(0, 0)) pour récupérer ma valeur, bah je peux récupérer n'importe quoi car plus tard dans mon code une variable peut prendre la place de la pile ou j'avais créée mon objet imgClone, or je n'ai jamais d'erreur en ajoutant des variables à la suite de ce code et je ne comprend pas pourquoi.

    J'espère que vous avez compris mon problème de compréhension

    Merci d'avance pour votre aide

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    imgClone et tab[0] ne sont pas les même variables car ce n'est pas un vector de référence sur cv::Mat, mais de cv::Mat. std::vector à fait une copie donc rien à craindre. Par contre, la copie peut être coûteuse et je ferrais tab.push_back(std::move(imgClone)) pour déplacer les données directement (ça ne changera rien si cv::Mat n'a pas de constructeur de déplacement).

  3. #3
    Membre très actif
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 274
    Par défaut
    Quand je fais tabMat.push_back(imgClone); ça reviens à faire tabMat.push_back(cv::Mat(imgClone)) ?
    Il y a donc passage par référence car le prototype du constructeur est cv::Mat(Mat & m) et donc tab[0] est la même chose que imgClone non ?

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Citation Envoyé par cosmoff Voir le message
    quand je fais tabMat.push_back(imgClone); ça reviens à faire tabMat.push_back(cv::Mat(imgClone)) ?
    Oui.

    Citation Envoyé par cosmoff Voir le message
    Il y a donc passage par référence car le prototype du constructeur est cv::Mat(Mat & m) et donc tab[0] est la même chose que imgClone non ?
    Non.

    Le constructeur prend une référence, est va faire une copie, on parle de constructeur de copie (il doit d'ailleurs manquer const dans ce que tu as mis). Le nouvel objet est alors totalement dissocié du précédent et vit sa vie en total indépendance.

  5. #5
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,

    D'après la documentation de cv::Mat dans OpenCV 4.0.1 :
    • Le constructeur de copie de cv::Mat ne fait pas une vraie copie. Il incrémente un compteur de références. La doc précise que, si on modifie le nouvel objet, alors cela modifie aussi l'ancien, car ils partagent les mêmes données.
    • Le destructeur de cv::Mat décrémente le compteur de références. Il ne libère la mémoire que si le compteur atteint 0.
    • Pour faire une vraie copie, on peut utiliser cv::Mat::clone.
    • Le constructeur de mouvement de cv::Mat apparaît dans la documentation, mais n'est pas documenté à l'heure où j'écris ces lignes.


    De mon point de vue, la conception de cv::Mat est aberrante, car elle est à mi-chemin entre la sémantique de valeur et la sémantique de référence.
    Si elle avait une vraie sémantique de valeur, alors toutes les copies auraient été profondes ou bien on aurait fait du Copy-On-Write.
    Si elle avait une vraie sémantique de référence, alors la mémoire aurait été gérée dans une autre classe.

    Cela dit, le code suivant devrait fonctionner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      {
        cv::Mat imgClone;
        img.copyTo(imgClone);
        tabMat.push_back(imgClone);
      }
    En effet, tabMat.push_back(imgClone) appelle le constructeur de copie de cv::Mat qui incrémente le compteur de références en le faisant passer de 1 à 2. À la fin du bloc, lors de la destruction de imgClone, le compteur de références passe de 2 à 1. Il ne vaut pas 0, donc les données de la matrice ne sont pas détruites.

    À part ça, on peut simplifier ce bloc de code en le remplaçant par une seule ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tabMat.push_back(img.clone());

  6. #6
    Membre très actif
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 274
    Par défaut
    En effet j'avais pas compris cette histoire de décrémentation lors du destructeur.

    merci beaucoup pour vos réponses.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Probleme de passage par référence.
    Par rouxc dans le forum C++
    Réponses: 4
    Dernier message: 04/11/2007, 14h52
  2. Réponses: 4
    Dernier message: 26/12/2005, 17h01
  3. Passage par référence
    Par difficiledetrouver1pseudo dans le forum Langage
    Réponses: 9
    Dernier message: 28/09/2005, 11h17
  4. Problème très rapide de passage par référence
    Par Noxexplorer dans le forum ASP
    Réponses: 2
    Dernier message: 23/06/2005, 10h02
  5. probleme avec une division par zéro
    Par jcharleszoxi dans le forum Langage SQL
    Réponses: 2
    Dernier message: 26/03/2003, 18h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo