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;
}
};
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
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
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
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...
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...
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...
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
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.
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
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.
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).
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).