Question

Dans beaucoup d'API C ++'S (ceux basés sur COM viennent à l'esprit) que make quelque chose pour vous, le pointeur sur l'objet qui est construit est généralement nécessaire comme un pointeur ** (et la fonction construira et init pour vous)

Vous voyez habituellement des signatures comme:

HRESULT createAnObject( int howbig, Object **objectYouWantMeToInitialize ) ;

-. Mais vous voyez rarement le nouvel objet passé comme une valeur de retour

En plus des gens qui veulent voir les codes d'erreur, quelle est la raison? Est-il préférable d'utiliser le modèle de ** plutôt qu'un pointeur renvoyé pour des opérations simples telles que:

wchar_t* getUnicode( const char* src ) ;

Ou serait-ce mieux être écrit:

void getUnicode( const char* src, wchar_t** dst ) ;

La chose la plus importante que je peux penser est de se rappeler de libérer, et la façon de **, pour une raison quelconque, a tendance à me rappeler que je dois désallouer ainsi.

Était-ce utile?

La solution

"En plus de vouloir les codes d'erreur"?

Qu'est-ce que vous fait penser il est a d'ailleurs. Les codes d'erreur sont à peu près la seule et unique raison. La fonction a besoin d'un moyen d'indiquer l'échec. C n'a pas d'exceptions, il doit le faire soit par un paramètre de pointeur, ou la valeur de retour, et la valeur de retour est idiomatiques, et plus facile à vérifier lors de l'appel de la fonction.

(Soit dit en passant, il n'y a pas de règle universelle que ** signifie que vous devez libérer l'objet. Ce n'est pas toujours le cas, et il est probablement une mauvaise idée d'utiliser quelque chose qui arbitraire pour vous rappeler les objets à nettoyer.)

Autres conseils

Deux raisons me viennent à l'esprit.

D'abord sont des codes d'erreur en fait. Autre que C ++, C n'a pas d'exceptions et COM est une API C. En outre, beaucoup des projets C ++ préfèrent ne pas utiliser des exceptions pour des raisons diverses. Il peut y avoir des cas où une valeur de retour ne peut pas signaler des erreurs, par exemple si votre fonction retourne un nombre entier, il peut y avoir aucune valeur entière, qui peut représenter un code d'erreur. Alors que les erreurs de signalisation avec des pointeurs est facile (NULL == erreur), certains concepteurs de l'API préfèrent signaler les erreurs de manière cohérente sur toutes les fonctions.

D'autre part, les fonctions ne peuvent avoir qu'une valeur de retour, mais les appelant peuvent créer plusieurs objets. Certaines fonctions de l'API Win32 prennent plusieurs pointeurs de pointeurs qui peuvent être remplis en option, si vous appelez ces fonctions avec des pointeurs non NULL. Vous ne pouvez pas revenir deux pointeurs, ou plutôt que ce serait difficile à utiliser, si la valeur de retour est une struct en valeur contenant plus d'un pointeur. Ici aussi une API cohérente est un objectif raisonnable à atteindre.

De nouveaux objets dans les arguments de fonction transmis par ** est mieux. Cela me prend un confort à l'utilisation future du changement void à bool par exemple pour revenir le succès d'une fonction ou d'autres informations fournissant fonctionne la fonction.

Réponse en une ligne:. Ceci est beaucoup mieux pour les codes d'erreur résultant

  

En plus des gens qui veulent voir les codes d'erreur, quelle est la raison?

Il y a quelques raisons à cela. L'un d'eux est l'écriture d'une interface qui est utilisable dans C (vous voyez cela dans le WinAPI et Windows COM).

La rétrocompatibilité est une autre raison (à savoir l'interface a été écrit comme ça et le casser serait maintenant briser le code existant).

Je partirais avec compatibilité C pour un principe de conception lors de l'utilisation du code comme celui-ci. Si vous deviez écrire en C ++, vous écririez

retval Myfunction(Result *& output);

au lieu de

retval Myfunction(Result ** output);

ou (encore mieux):

Result *Myfunction();

et ont la fonction lancer une exception en cas d'erreur.

Je ne suis pas sûr que je suis d'accord que est la meilleure façon de le faire ... cela pourrait être mieux:

Object * createAnObject(int howbig, HRESULT * optPlaceResultCodeHereIfNotNull = NULL);

De cette façon, il n'y a pas embêter avec double indirection (qui peut être un peu difficile pour les gens qui ne sont pas habitués), et les gens qui ne se soucient pas des codes de résultats ne doivent pas inquiéter sur le second argument du tout ... ils peuvent simplement vérifier pour voir si la valeur de retour est NULL ou non.

En fait, puisqu'il est C ++, vous pouvez rendre les choses encore plus facile, en utilisant la surcharge de fonction:

Object * createAnObject(int howbig);
Object * createAnObject(int howbig, HRESULT & returnResultCode);

Tout appel de méthode dans un appel COM doit être HRESULT. Les codes de retour se mis à profit dans le cadre et le passage d'un double pointeur est un moyen bien connu pour obtenir l'objet créé.

Ne pas répondre à votre question, mais un commentaire que votre question a quelques réflexions que j'ai sur COM / DCOM programmation en C ++.

Tous ces « pointeur vers pointeur » « pointeur », et la gestion de la mémoire et le comptage de référence sont les raisons pour lesquelles je Shy loin de faire la programmation COM avec C ++. Même avec ATL en place, je ne l'aime pas pour la simple raison qu'il ne semble pas assez naturel. Cela dit, je ne fais quelques projets en utilisant ATL.

À l'époque, l'alternative est l'utilisation de VB. code VB semble plus naturel pour la programmation COM ou DCOM.

Aujourd'hui, j'utiliser C #.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top