Question

Si j'utilise le mot clé new dans ma bibliothèque (construite différemment de l'application principale), lorsque je le supprime dans mon application principale avec delete , existe-t-il une chance que je puisse avoir un crash / une erreur?

Était-ce utile?

La solution

oui en effet. En particulier, vous constatez que les problèmes avec les tas de débogage / édition sont différents, même si votre bibliothèque utilise un nouvel emplacement ou tout autre tas personnalisé, vous aurez un problème. Le problème Debug / Release est de loin le plus courant.

Autres conseils

Cela dépend. Si vous parlez d'une bibliothèque statique, tout ira bien: le code s'exécutera dans le même contexte que le programme principal, à l'aide de la même bibliothèque d'exécution C ++. Cela signifie que new et delete utiliseront le même segment de mémoire.

Si vous parlez d'une bibliothèque partagée (une DLL), vous ne pourrez probablement pas vous en contenter. Le code exécuté dans la DLL peut utiliser une bibliothèque d'exécution C ++ différente, ce qui signifie que la disposition du segment de mémoire sera différente. La DLL utilise peut-être un tas différent.

L'appel de delete (dans le programme principal) sur un pointeur attribué par la DLL (ou inversement) entraînera (au mieux) un crash immédiat ou (au pire) une corruption de la mémoire qui prenez un moment pour retrouver votre trace.

Vous avez plusieurs options. La première consiste à utiliser la " méthode d’usine " motif pour créer et supprimer ces objets:

Foo *CreateFoo();
void DeleteFoo(Foo *p);

Celles-ci ne doivent pas être implémentées dans le fichier d'en-tête.

Vous pouvez également définir une méthode Destroy sur l'objet:

class Foo
{
    ~Foo();

public:
    virtual void Destroy();
};

... encore une fois, ne l'implémentez pas dans le fichier d'en-tête. Vous l'implémenteriez ainsi:

void Foo::Destroy()
{
    delete this;
    // don't do anything that accesses this object past this point.
}

Notez que le destructeur de Foo est privé, vous devez donc appeler Foo :: Destroy .

Microsoft COM fait quelque chose de similaire en définissant une méthode Release qui supprime l’objet lorsque son nombre de références tombe à zéro.

Oui, vous le ferez. Une solution simple consiste à fournir des fonctions Créer et Supprimer dans votre bibliothèque qui peuvent être appelées à partir de l'application principale. La fonction Créer effectuera la nouvelle opération et renverra un pointeur, qui sera ensuite transmis à la fonction Supprimer pour suppression.

C’est un problème que je n’ai vu que sous Windows.

Les systèmes Unixish ne prennent pas l'habitude de forcer les bibliothèques partagées à se lier à différentes versions de la même bibliothèque au sein du même programme et tous les symboles chargés sont visibles de manière globale. Cela signifie que si un objet est alloué dans une partie du code et supprimé dans une autre, les deux utilisent la même bibliothèque système pour le faire.

Je dois dire que ce problème créé par Windows avec ses différentes DLL d’exécution en C est vraiment gênant et peu naturel pour un programmeur en C. Regardez la bibliothèque C; il a des fonctions comme strdup qui malloc la chaîne et attend du programmeur qu'il appelle free () dessus. Mais faites la même chose dans votre propre bibliothèque sous Windows et attendez l'explosion. Vous devrez également attendre, car cela ne se produira pas pendant le développement, mais seulement après que vous ayez donné la DLL compilée à un autre SAP médiocre.

l'ancienne nouvelle chose a déjà traité de la question . Il donne également une liste des principales solutions de Microsoft.

Vous avez tout à fait raison de dire qu'il y a un problème, mais dans la plupart des cas, il existe une solution encore plus simple que celle proposée par les autres réponses (à ce jour). Vous pouvez continuer à utiliser new et delete librement - tout ce que vous avez à faire est de surcharger new et delete pour chaque classe de votre bibliothèque pouvant être utilisée indépendamment des limites de DLL.

Personnellement, je viens de définir une classe simple pour fournir les fonctionnalités nécessaires:

class NewDelete
{
    public:
        void *operator new (size_t size);
        void operator delete (void *memory);
        void *operator new (size_t size, void *ptr);
        void operator delete (void *memory, void *ptr);
};

Tant que ces quatre fonctions membres sont toutes définies dans la même DLL, toute classe dérivant de cette classe est automatiquement "DLL-safe". - new et delete peuvent être utilisés normalement sur eux sans se soucier des limites des DLL.

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