0
votes

Fonction de retour de type de référence: Comment retourner (facultatif) objet

J'ai une application multithreaded C ++ pouvant appeler de n'importe quel thread une fonction comme suit, pour obtenir un objet à partir d'une liste / vecteur. XXX PRE>

Note: La portée Voici de comprendre certaines meilleures pratiques liées aux retours de fonction par référence, valeur ou pointeur, pardonnez donc une pseudo-code ou des déclarations manquantes (I Utilisation de verrouillage / déverrouillage, globalclass code> est un singleton global, etc. ...). em> p>

Le problème ici est que si le myObject code> à cet indice est supprimé à l'intérieur globalclass code> à un certain point J'utilise un mauvais pointeur ( obj code>). P>

Je pensais donc à retourner une copie forte> de l'ojjject: p>

     const MyObject& GlobalClass::getObject(int index) const
     {
          /* mutex lock & unlock */

          if (m_list.hasValueAt(index))
              return *m_list[index];
          else{
              MyObject* obj = new MyObject();
              return *obj ;
          }
     }


5 commentaires

Utilisez std :: en option ?


Oh et la troisième version de votre programme (retourner une référence) ont toujours le problème que vous mentionnez pour le premier, vous pouvez renvoyer une référence à un objet qui est supprimé ultérieurement et en faisant une référence invalide.


Utilisez un pointeur faible . C'est faire votre vecteur un vecteur de partagé_ptr , puis renvoyez un faible_ptr . Si un autre thread supprime l'objet d'origine, vous pouvez tester pour cela sur votre objet FAID_PTR. Et les indicateurs faibles copient de manière raisonnablement efficace


@SomeProGrammerDude: J'ai fait un test ( cpp.sh/7k5t2 ) pour comprendre le cas, et il semble que la référence est toujours la valeur après la suppression. Qu'est-ce qui me manque?


La référence n'est pas valide. C'est comme un pointeur sur un objet supprimé, vous pouvez toujours désirer le pointeur, mais cela conduira à comportement indéfini .


3 Réponses :


5
votes

Vous avez plusieurs choix:

  1. Utilisez un std :: partagé_ptr Si "Get" transmettez la propriété de l'objet à l'appelant. De cette façon, l'objet ne peut pas sortir de la portée. Bien sûr, l'appelant n'est pas au courant de son arrivée.
  2. Utilisez un std :: faible_ptr . Cela a la même signification de 1., mais le PTR peut être réinitialisé. Dans ce cas, l'appelant peut détecter si l'objet a été supprimé.
  3. Utilisez std :: optionnel comme suggéré dans un commentaire et renvoyez une copie ou une référence. L'utilisation d'un type de référence comme argument de facultatif n'évite pas le problème de l'objet supprimé de sorte que la référence peut également devenir invalide. Une copie éviterait cela, mais cela peut être trop cher, comme dit.

    lire à travers les lignes, vous semblez suggérer que l'appelant utilisera le pointeur immédiatement après l'appel et pour une durée limitée. Ainsi 1. et 2. sont équivalents et semble correspondre à vos besoins.

    voir Cette introduction aux pointeurs intelligents pour plus de détails.


4 commentaires

Peut également être une enveloppe de référence optionnelle.


Oui, mais si l'objet pointu est supprimé, la référence deviendra invalide. Donc, peut-être que l'approche intelligente du pointeur semble éviter cela.


C'est pour l'option 3, il ne doit pas nécessairement être une copie si OP connaît la durée de vie de l'objet.


Oui, mais l'OP indique que c'est un programme multithreadé, alors je suppose que cela n'est pas connu si les objets sont utilisés dans la même chose ou dans des threads différents.



0
votes

Vos problèmes semblent découler du fait que votre programme est multithreadé - une autre voie à suivre (et pour le pointeur brut ou la version de référence Facultatif Version de renvoi: Seule la voie à suivre, peut-être à court d'une manière La refonte complète) est que vous devez exposer le mutex à l'extérieur de la portée de la fonction pour accomplir ce dont vous avez besoin. Ceci vous pouvez accomplir de plusieurs manières, mais le moyen le plus simple d'illustrer est ce qui suit: xxx


0 commentaires

1
votes

Si vous souhaitez éviter de copier l'objet, il n'y a que deux cas possibles:

  1. L'entrée m_list renvoyé par getObject est / peut être supprimé simultanément par un autre fil. Si vous ne copiez pas cet objet à l'avance, vous ne pouvez rien faire dans GetObject pour empêcher tout à coup un autre thread d'avoir une référence / pointer. Toutefois, vous pouvez faire chaque entrée de m_list être un std :: partagé_ptr et retourner cela directement. La gestion de la mémoire se produira automatiquement (mais méfiez-vous de la surcharge potentielle dans le comptage de référence de partagé_ptr , ainsi que la possibilité d'embûts).

  2. Vous avez (ou ajoutez) un mécanisme pour vous assurer que les objets ne peuvent être supprimés que de m_list si aucun autre thread ne contient actuellement du pointeur / référence. Cela dépend beaucoup de votre algorithme, mais c'est peut-être par exemple. Soyez possible de marquer des objets pour la suppression, puis supprimez-les plus tard dans une section synchrone.


0 commentaires