6
votes

Une bibliothèque oblige les surcharges globales de nouveau / Supprimer sur moi!

Je maintient un plugin (implémenté comme une DLL) pour une grande application à la source fermée. Cela fonctionne bien depuis des années. Toutefois, avec la dernière mise à jour de son SDK, les opérateurs mondiaux surchargés par le fournisseur ont surchargé des opérateurs mondiaux et supprimés. Cela provoque beaucoup de problèmes pour moi. Ce qui se passe, c'est que mon plugin alloue une chaîne. Je passe cette chaîne en une bibliothèque lié statiquement liée qui la modifie (changements de la longueur de la longueur de la réaffectation). Mon application se bloque.

La raison est bien entendu que la chaîne vit sur le fournisseur alloué à un tas personnalisé. La bibliothèque liée statique ne connaît rien de ce tas et tente d'utiliser les opérateurs neufs / Supprimer par défaut sur cette mémoire. Boom.

La question est la suivante: comment puis-je garder mon code propre et éviter d'utiliser les opérateurs du vendeur? Il n'y a pas de macro de préprocesseur conditionnel. Je ne peux pas éviter d'inclure l'en-tête d'incrimination car il contient 2000 lignes plus de code dont j'ai besoin pour le plugin. Je ne peux pas passer l'allocator fourni dans l'autre bibliothèque car elle ne fournit aucun mécanisme pour cela. J'ai déjà bugié le vendeur à ce sujet. Je ne sais pas quoi d'autre pour pouvoir essayer?

addendum: Après un débat animé, j'ai réussi à convaincre le fournisseur de supprimer à nouveau les surcharges de la prochaine version du SDK. J'ai résolu mon problème immédiat en piratant simplement le SDK actuel et en supprimant les surcharges manuellement. Merci pour toutes les suggestions de ce fil. Ils ont servi comme des arguments et une autre "preuve" de la raison pour laquelle les surcharges étaient une mauvaise idée en premier lieu.


5 commentaires

Devez-vous éviter de changer la bibliothèque statique?


Je pourrais le changer dans ce cas car il est open source. Mais j'aimerais vraiment éviter de faire monter mes modifications avec chaque nouvelle version. Je préférerais aussi beaucoup que je préfère une solution qui fonctionne avec des libs que je n'ai pas d'accès source à ...


En outre, parlez-vous de STD :: String, char * s ou un autre type de chaîne?


Vous ne pouvez rien faire si la bibliothèque réaffecte votre chaîne et ne donne pas accès à son allocator. Continuez à les déranger, leur bibliothèque est cassée.


char * dans ce cas particulier. Mais je pense que cela est effectivement non pertinent car le problème reste pour toutes les allocations.


4 Réponses :


0
votes

Une option consiste à créer votre propre nouvel opérateur surchargé pouvant être mis en œuvre en termes de malloc.

Ceci pourrait être défini comme: xxx

Ceci peut alors être appelé par vous comme myClass * myClass = nouveau (EmyNew) myClass;

Comme cela est mis en œuvre en termes de malloc, il devrait se comporter comme prévu. Le seul abatteur est que vous devrez remplacer toutes les instances de l'endroit où vous avez utilisé de nouvelles.


2 commentaires

Malheureusement, ce n'est pas une option puisque je ne sais pas ou ne contrôle pas "toutes les instances où j'ai utilisé de nouveaux". Pensez à STL, bibliothèques liées, etc.


STL peut être surmonté avec l'utilisation d'un allocator personnalisé.
Les bibliothèques liées doivent être en sécurité en raison du fait qu'ils ne sont pas compilés contre vos fichiers d'en-tête.



1
votes

Vous pouvez utiliser un autre nouveau dans votre espace de noms:

namespace MyNS {
    // Declare your new/delete operators here
    // and also declare a class implementing the same interface as std::allocator
    // using your newly created memory management functions.
    // Don't forget to put all your classes in the namespace.
    // (if you don't have one already)
}


3 commentaires

Mettre votre nouveau / Supprimer dans votre propre espace de noms ne vous assurera pas qu'ils sont toujours utilisés (les types d'espace de noms sont souvent référencés dans d'autres espaces de noms). En fait, cela entraînera probablement plus de problèmes d'inadéquation d'allocator. La définition d'un nouvel allocator à utiliser avec des types de stl est une question orthogonale, un tel type n'a rien à voir avec le nouveau / Supprimer mondial et ne doit pas nécessairement être dans un espace de noms particulier.


Et, les allocateurs personnalisés ne sont pas dérivés de STD :: ALLOCATOR. Voir le lien dans ma réponse.


Corrigé l'erreur sur l'héritage. Néanmoins, si des opérateurs neufs / Supprimer sont déclarés dans un espace de noms, tout dans cet espace de noms les utilisera. Bien sûr, cela n'est pas parfait (comme vous l'avez dit, d'autres classes non dans cet espace de noms ne les utiliseront pas). Mieux est de restaurer le nouveau NOUVELLIAL ORIGINAL. Une bonne idée lorsque la surcharge utilise le même tour de surcharge que celui utilisé par la nouvelle "NOTHROWO" NEW.



5
votes

Si vous compilez dans (via Inclusion d'en-tête), un opérateur neuf / Supprimer (s) remplacé (s), alors tous les appels de votre code sur New / Supprimer les utiliseront. Il n'y a aucun moyen de reprogrammer la reprogrammation (erreurs de liaison) ou seulement la remplacer partiellement, etc.

Il est mauvais de formulaire pour remplacer les opérateurs mondiaux / Supprimer, du tout. C'est une mauvaise idée. Si vous ne réalisez pas pourquoi c'est une mauvaise idée, vous n'êtes pas qualifié pour le faire. Si vous réalisez pourquoi c'est une mauvaise idée, vous êtes qualifié de le faire, mais vous choisirez généralement de ne pas le faire.

Définition d'un nouveau / Supprimer global est exponentiellement plus mauvais dans un composant que vous prévoyez que les gens incluent directement dans leur projet. C'est votre travail de client d'aider le vendeur à faire comprendre la gravité de la situation ou d'arrêter d'être leur client.

Vous pouvez définir un type d'allocator personnalisé (voir cette Lien pour un bon tutoriel sur la manière de le faire, l'interface nécessaire, etc.) et l'utiliser exclusivement avec vos types STL (c'est un argument de modèle).

Pour Shared_Ptr, vous devez faire quelque chose un peu différent: il faut un objet de Deleter en tant que paramètre sur le constructeur si vous ne voulez pas le comportement "Supprimer P" par défaut. Ce n'est pas un allocator personnalisé; C'est juste un foncteur unitaire régulier.


1 commentaires

Vous avez raison d'être coincé avec le nouveau et le nouveau supprimé. Cependant, je suis en désaccord avec votre affirmation qui remplacera la nouvelle et la suppression mondiale est une forme de mauvaise forme. Je l'ai fait et j'ai travaillé sur des dizaines de projets où d'autres personnes l'ont fait. En règle générale, vous ne remplissez jamais de nouvelles et supprimez dans les bibliothèques, car cela peut être une douleur pour vos utilisateurs. C'est pourquoi de nombreuses bonnes bibliothèques suivent la Convention STL permettant aux utilisateurs de spécifier leurs propres allocateurs pour des objets. Mais le remplacement de la nouvelle et la suppression est très pratique pour la gestion des ressources système, il vous suffit de savoir ce que vous faites.



2
votes

N'est-il pas possible de faire cela:

namespace evil{

#include "evil_header.h"

}


0 commentaires