Comment surcharger new
y delete
pour un dll
. J'ai écrit des opérateurs surchargés en tant que partie de la dll, mais le client se lie avec ceci dll
n'utilise pas overloaded new and delete
Réponses
Trop de publicités?Voici ce que dit la norme C++ à ce sujet, dans la section 17.6.4.6/3 :
Les définitions du programme (des opérateurs de création et de suppression) sont utilisées au lieu des versions par défaut fournies par l'implémentation. Ce remplacement a lieu avant le démarrage du programme. Les définitions du programme ne doivent pas être spécifiées en tant que
inline
. Aucun diagnostic n'est nécessaire.
Si vous lisez attentivement ce texte, il explique exactement le problème que vous rencontrez. Il y a une sorte de "catch 22" qui se produit ici.
D'une part, vous ne pouvez pas avoir les définitions de vos opérateurs new/delete compilées à l'intérieur de la DLL parce que les new/delete surchargés ne peuvent pas être liés dynamiquement (ceci parce que new/delete pourrait être nécessaire pendant l'initialisation statique, avant le chargement de la DLL, donc vous auriez des opérateurs new/delete incohérents avant et après le chargement de la DLL, et c'est un comportement indéfini).
D'un autre côté, vous ne pouvez pas simplement placer vos définitions d'opérateurs de type "new/delete" dans vos fichiers d'en-tête de DLL, car elles devraient être marquées inline
afin de satisfaire à la règle de la définition unique (ODR), qui, à son tour, ne satisfait pas à la clause ci-dessus. L'exigence selon laquelle ils ne doivent pas être marqués inline
est probablement là parce qu'une définition de fonction marquée inline
n'a pas de lien, ce qui fait que chaque unité de traduction utilise sa propre version compilée (ou des expansions en ligne), ce qui est normalement acceptable, mais pas pour l'allocation dynamique de mémoire.
Les deux captures ci-dessus sont motivées par le fait que, pour être correct, il faut généralement garantir que la mémoire allouée à l'aide de new
est désallouée avec l'objet correspondant delete
(c'est-à-dire "compilées ensemble", pour ainsi dire, ou toutes deux par défaut). Par exemple, si vos opérateurs new/delete s'appuient sur un appel malloc/free sous-jacent, vous vous appuyez sur le tas utilisé par l'unité de traduction qui a appelé l'opérateur new/delete, entre une DLL et un exécutable, rien ne garantit que ce tas sera le même (en fait, sous Windows, en particulier, il ne l'est pas, les deux modules utilisent deux tas distincts pour les allocations de mémoire dynamique).
Donc, la solution à votre problème, comme le dit Rook, est "ne faites pas ça". Ne surchargez pas les opérateurs new/delete pour les objets DLL parce qu'il n'y a pas de méthode propre pour le faire correctement, quelle que soit la façon dont vous tournez et tournez votre code, il se résumera toujours au même problème mentionné ci-dessus.
Ce que vous pouvez et devez faire à la place, c'est utiliser un modèle de fonction d'usine pour vos objets DLL et renvoyer un pointeur intelligent (tel qu'un fichier std::shared_ptr
) avec un suppresseur personnalisé qui s'appuie sur une répartition dynamique de la suppression vers le site où l'objet a été créé. Ceci est inspiré d'une technique de Chad Austin . J'ai fait quelque chose de très similaire ici .
Vous pouvez essayer d'écrire vos propres fonctions malloc et delete, puis créer une définition C qui contient essentiellement le code permettant de remplacer new et delete et d'appeler ces fonctions malloc et delete personnalisées.
De cette façon, vous pourriez faire quelque chose comme
MODULE_START()
// CODE HERE
MODULE_END()
et cela devrait fonctionner sans problème.