Est-ce une mauvaise façon de renvoyer un pointeur alloué à une fonction?

Avant boost::shared_ptr , était-il considéré comme une mauvaise pratique de renvoyer un pointeur alloué à une fonction depuis une fonction, étant donné que l’appelant devra se rappeler de free() cet object?

Ou était-ce considéré comme “normal”?

Je ne considère pas cela comme une mauvaise pratique, tant que votre API fournit également une fonction équivalente XXX_free (ou XXX_close , XXX_clearup ou autre) que le code client peut appeler une fois le pointeur terminé.

Ainsi, vous disposez d’une API cohérente et symésortingque, en ce sens que la responsabilité de la durée de vie d’un object de tas est conservée à un endroit.

Cette approche est également susceptible de libérer des ressources plus complexes. Par exemple, si le pointeur renvoyé est dirigé vers une structure allouée dynamicment qui comporte à son tour des membres pointant vers une mémoire allouée dynamicment, la procédure de nettoyage entière peut être masquée / extraite du code client.

Vous avez marqué votre question C. En C, c’est très courant, par exemple fopen renvoie FILE * qui doit ensuite être désalloué en appelant fclose .

Si vous vouliez étiqueter C ++, c’est plus compliqué. Les anciennes bases de code (milieu des années 1990 et antérieures) faisaient souvent passer des pointeurs nus aux objects. Des bibliothèques entières sockets en charge commercialement étaient basées sur ce modèle (OWL de Borland, Microsoft MFC).

Si vous avez besoin de le faire, il est courant de fournir votre propre fonction “libre” qui prend et libère votre pointeur atsortingbué. Cela empêche l’utilisateur d’utiliser une implémentation libre incompatible qui pourrait corrompre la mémoire.

Vous trouverez des exemples des deux méthodologies: une fonction allouant de la mémoire et renvoyant un pointeur, ou une fonction acceptant un pointeur sur un espace déjà alloué.

Tant que l’interface est clairement documentée et suivie, il y a des aspects positifs et négatifs pour les deux. Par exemple, comme de nombreuses personnes l’ont mentionné, une bibliothèque fournissant une fonction d’allocation devrait normalement fournir une fonction de suppression. En tant que client, vous ne savez pas quelle méthode a été utilisée pour allouer de la mémoire dans cette fonction sophistiquée, vous (le client) ne savez pas quelle méthode doit être utilisée pour la détruire.

D’autre part, la logique peut être plus complexe lorsque vous devez vous préoccuper de l’allocation de stockage, la transférer à quelque chose qui peut ou non effectuer le travail attendu, puis déterminer si ce stockage est toujours pertinent, etc. En fonction de l’ utilisation de la mémoire, masquant les détails de l’allocation, pourrait également consortingbuer à en optimiser l’optimisation.

La réponse courte est: c’est vous qui décidez. La mauvaise façon de faire est de choisir quelque chose et d’être incohérent ou incertain dans l’interface.

C’était et rest commun, car c’est à peu près le seul moyen de gérer des bibliothèques construites avec différentes exécutions sur certains systèmes d’exploitation. Par exemple, sous Windows, le partage de plusieurs bibliothèques d’exécution VC ++ dans un seul exécutable ne fonctionnera normalement correctement que si les bibliothèques sont responsables de leur propre gestion de la mémoire, y compris à la fois l’allocation des objects et leur disposition. shared_ptr et des outils similaires peuvent réellement causer des problèmes dans ce cas.

Cela étant dit, le nom de la fonction et / ou la documentation (lorsque cela est correctement effectué) rendrait évident le contraire. Il était également courant d’avoir une fonction DeleteXXX () correspondante pour gérer l’appel gratuit.

En règle générale, vous ne renverriez qu’un pointeur à partir d’une fonction create_blah () explicite.

Plus commun est de passer dans un pointeur (à un pointeur), qui s’il est nul a été alloué par la fonction.

En réalité, un meilleur idiome (utilisé par les interfaces COM) consiste à exiger la création d’un pointeur sur l’appelant avant le sharepoint l’appel de la fonction et à écrire une fonction qui accepte un double pointeur.

Par exemple :

     HRESULT CreateDevice (
       [en] adaptateur UINT,
       [en] D3DDEVTYPE DeviceType,
       [en] HWND hFocusWindow,
       [en] DWORD BehaviorFlags,
       [in, out] D3DPRESENT_PARAMETERS * pPresentationParameters,
       [out, retval] IDirect3DDevice9 ** ppReturnedDeviceInterface
     )

Ainsi, l’appelant est responsable de la création du pointeur et de l’appel de la fonction d’allocation, il est donc plus susceptible de se rappeler d’appeler la fonction de désallocation (ce qui dans le cas de COM nécessite que vous appeliez une méthode ->Release() sur l’object COM)

Mais je pense que l’adoption de fonctions Création / Destruction, combinée avec le passage de doubles pointeurs, est un meilleur moyen de rappeler au destinataire un object atsortingbué au tas à nettoyer après l’avoir utilisé.

Je suis d’accord avec Oli sur le fait que les fonctions Create / Destroy sont beaucoup plus symésortingques et que l’existence de la fonction Destroy devrait permettre à l’utilisateur de l’API de penser que ces objects qu’il récupère des fonctions Create ne disparaîtront pas d’eux-mêmes et qu’ils (Destroy fcns) doivent être appelés.