Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Pointeur intelligent en paramètre de fonction

14 réponses
Avatar
Michael
Bonjour à tous,

C'est un peu HS puisqu'en l'occurence les pointeurs intelligents sont des
CComPtr, issus de la bibliothèque ATL, et qui permet de gérer des objets
COM.

Mais je pense que le principe est le même que pour des boost::shared_ptr
par exemple.

Passons au vif du sujet:

Pourquoi est ce que le code suivant ne fonctionne pas?
Est-ce qu'il existe une autre manière de passer des CComPtr en
paramètre de fonction?

class toto
{
private:
CComPtr<IGraphBuilder> pGraph;
public:
void SetGraph(CComPtr<IGraphBuilder> graph)
{
pGraph = graph;
}
};

class foo
{
private:
toto t;

CComPtr<IGraphBuilder> pGraph;

// blablabla...
public:
foo()
{
t.SetGraph(pGraph);
}
};

Après l'appel de t.SetGraph(pGraph), un appel à
IGraphBuilder::Release() est déclenché, ce qui fait que mon objet
pGraph est réinitialisé...

Comment je dois passer ça?

1) Passer le pointeur brut:

void toto::SetGraph(IGraphBuilder * graph)
{
pGraph = graph;
}

foo::foo()
{
t.SetGraph(pGraph);
}

2) Passer par un pointeur de CComPtr?

void toto::SetGraph(CComPtr<IGraphBuilder> * ppgraph)
{
pGraph = *ppgraph;
}

foo::foo()
{
t.SetGraph(&pGraph);
}

J'avoue être un peu perdu avec le comptage des références...

Est-ce que quelqu'un peut éclairer ma lanterne?

Merci d'avance

4 réponses

1 2
Avatar
Arnaud Meurgues
Michael wrote:

Mais du coup, je ne comprends pas pourquoi un appel à Release
réinitialiserait l'objet.
Ai-je raté quelque chose dans l'énoncé de la question ?


Ben je ne suis pas sûr, mais je crois que, lorsque Release amène le compteur
interne de l'objet COM IGraphBuilder à 0, celui-ci efface tous les filtres
qui y sont connectés...


D'accord. Mais ce que je voulais dire, c'est que normalement, le
compteur de référence ne devrait jamais passer à zéor simplement parce
que vous le passez en paramètre :

Après l'appel de t.SetGraph(pGraph), un appel à
IGraphBuilder::Release() est déclenché, ce qui fait que mon objet
pGraph est réinitialisé...


Or foo::pGraph, lorsqu'il a été initialisé (où ça, au fait), a dû faire
un AddRef() sur IGraphBuilder correspondant, passant son compteur de
référence à 1.

Si foo::foo() appelle t.SetGraph(pGraph), alors :
1- on crée une copie du CComPtr pour le paramètre de la fonction qui
appelle AddRef() => cptref = 2
2- dans toto::SetGraph(), on fait pGraph = graph, ce qui rajoute un
CComPtr sur l'objet COM, et fait un appel à AddRef() => cptref = 3
3- en sortant de toto::SetGraph(), le paramètre est détruit, ce qui
appelle Release() => cptref = 2

Donc, effectivement, Release() est appelé, mais il ne devrait pas passer
le compteur de référence à 0, et cela ne devrait donc pas avoir pour
effet une « réinitialisation » de l'objet COM.

Donc, à mon sens, vous utilisez correctement les CComPtr, d'après ce que
vous avez montré ici, mais il y a un autre problème autre part.

Accessoirement, le premier problème que je vois (mais c'est sans doute
dû à une simplification excessive de votre exemple), c'est que
foo::foo() appelle t.SetGraph(pGraph) alors que pGraph n'a pas été
initialisé.
--
Arnaud


Avatar
Michael
Donc, effectivement, Release() est appelé, mais il ne devrait pas passer
le compteur de référence à 0, et cela ne devrait donc pas avoir pour
effet une « réinitialisation » de l'objet COM.

Donc, à mon sens, vous utilisez correctement les CComPtr, d'après ce que
vous avez montré ici, mais il y a un autre problème autre part.


Effectivement... J'ai changé la définition des fonctions, et maintenant je
passe les CComPtr par référence et ça roule...

Accessoirement, le premier problème que je vois (mais c'est sans doute
dû à une simplification excessive de votre exemple), c'est que
foo::foo() appelle t.SetGraph(pGraph) alors que pGraph n'a pas été
initialisé.


Effectivement, c'était du à une simplification excessive. foo initialise bien
foo::pGraph avant l'appel de toto::SetGraph...

Avatar
Arnaud Meurgues
Michael wrote:

Effectivement... J'ai changé la définition des fonctions, et maintenant je
passe les CComPtr par référence et ça roule...


C'est bizarre, parce que, normalement, ça devrait fonctionner aussi par
valeur.

Effectivement, c'était du à une simplification excessive. foo initialise bien
foo::pGraph avant l'appel de toto::SetGraph...


Du coup, je ne m'explique pas un passage à 0 du compteur de référence.

--
Arnaud

Avatar
Sylvain
Michael wrote on 26/06/2006 16:50:

Ben je ne suis pas sûr, mais je crois que, lorsque Release amène le compteur
interne de l'objet COM IGraphBuilder à 0, celui-ci efface tous les filtres
qui y sont connectés...


non pas exactement, si le ref count de l'interface IGraphBuilder est à
zéro, l'object est détruit (tout Release() est équivalent à "if
(--refCounter == 0) delete this;").

se détruisant le GB va réleaser tous les filtres qui lui été attachés
qui sont souvent mono-référencés (s'ils sont crées par
CComQIPtr<interface, IID>, une interface d'IID non attachée est
construite (contrairement à CoCreateInstance qui fait un AddRef); le
AddFilter seul fait un AddRef, qui est balancé par le destructeur du GB
(ou très certainement par un AddFilter d'une même interface - je n'ai
pas vérifié le src).

Sylvain.

1 2