86 votes

Existe-t-il une utilisation légitime de void *?

Est-il légitime d'utiliser des void* en C++? Ou était-ce instauré parce que C était?

Juste pour résumer ma pensée:

Entrée: Si nous voulons permettre à plusieurs types d'entrée, nous pouvons la surcharge de fonctions et de méthodes, sinon, nous pouvons définir une classe de base commune, ou d'un modèle (merci de mentionner cela dans les réponses). Dans les deux cas, le code est plus descriptif et moins sujette aux erreurs (à condition de la classe de base est mis en œuvre dans un façon saine).

Sortie: je ne peux pas penser à une situation où j'préférez les recevoir en void* par opposition à quelque chose dérivée à partir d'une classe de base.

Juste pour préciser ce que je veux dire: je ne suis pas spécifiquement demandé si un cas d'utilisation pour void*,, mais si il y a un cas où l' void* est le meilleur ou le seul choix disponible. Qui a été parfaitement répondu par plusieurs personnes ci-dessous.

80voto

Basile Starynkevitch Points 67055

void* est au moins nécessaire que le résultat d' ::operator new (également chaque operator new...) et d' malloc et que l'argument du placement new de l'opérateur.

void* peut être considéré comme le commun supertype de chaque type de pointeur. Il n'est donc pas exactement le sens pointeur void, mais le pointeur de quoi que ce soit.

BTW, si vous souhaitez conserver certaines données pour plusieurs sans rapport avec les variables globales, vous pouvez utiliser quelques - std::map<void*,int> score; puis, après avoir déclaré mondiale int x; et double y; et std::string s; ne score[&x]=1; et score[&y]=2; et score[&z]=3;

memset veut un void* adresse (générique)

Aussi, POSIX systèmes ont dlsym et son type de retour, de toute évidence devrait être void*

28voto

Matthieu M. Points 101624

Il y a de multiples raisons de l'utilisation d' void*, les 3 plus courants sont:

  1. l'interaction avec une bibliothèque en C à l'aide de void* dans son interface
  2. type-erasure
  3. la dénotation de l'onu de type de mémoire

Dans l'ordre inverse, ce qui dénote de l'onu de type de mémoire avec void* (3) au lieu de char* (ou variantes) aide à la prévention des accidents de l'arithmétique des pointeurs; il y a très peu d'opérations disponibles sur l' void* sorte qu'il est généralement besoin de casting avant d'être utile. Et bien sûr, comme avec la char* il n'y a pas de problème d'aliasing.

Type-erasure (2) est encore utilisée en C++, en conjonction avec des modèles ou pas:

  • code non générique contribue à la réduction des binaires de ballonnements, il est utile dans le froid chemins, même dans le code générique
  • non génériques de code est nécessaire pour le stockage parfois, même dans les conteneur générique comme std::function

Et évidemment, lorsque l'interface vous traitez avec les utilisations void* (1), vous avez peu de choix.

15voto

Joshua Points 13231

Oh oui. Même en C++, parfois, nous allons avec void * plutôt que d' template<class T*> parce que parfois, le code supplémentaire à partir du modèle d'expansion pèse trop.

Souvent, je l'utiliserais comme la mise en œuvre effective de la type, et le type de modèle hériter du et envelopper la jette.

Aussi, la coutume de la dalle allocateurs (opérateur de nouvelles implémentations) void *. C'est une des raisons pour lesquelles g++ ajouté une extension de permettre pointeur arithmatic sur void * comme si c'était de taille 1.

10voto

black Points 2917

Entrée: Si nous voulons permettre à plusieurs types d'entrée, nous pouvons surcharge les fonctions et les méthodes

Vrai.

sinon, nous pouvons définir une base commune classe.

Cela est en partie vrai: que faire si vous ne pouvez pas définir une classe de base commune, une interface ou similaires? Pour définir ceux que vous avez besoin d'avoir accès au code source, ce qui n'est pas souvent possible.

Vous n'avez pas parlé de modèles. Cependant, les modèles ne peuvent pas vous aider avec le polymorphisme: ils travaillent avec des types statiques c'est à dire connu au moment de la compilation.

void* peut être considéré comme le plus petit dénominateur commun. En C++, en général, vous n'avez pas besoin d'elle parce que (i) vous ne pouvez pas intrinsèquement faire beaucoup avec elle et (ii) il y a presque toujours de meilleures solutions.

Encore plus loin, vous finissent généralement sur la conversion à d'autres types de béton. C'est pourquoi, char * est généralement mieux, même si cela peut indiquer que vous vous attendez à un C-chaîne de style, plutôt que d'un pur bloc de données. C'est pourquoi,void* est mieux que char* , car il permet de cast implicite à partir d'autres types de pointeur.

Vous êtes censé recevoir des données, de travailler avec elle et de produire une sortie; pour y parvenir, vous devez connaître les données que vous travaillez avec, sinon vous avez un problème différent qui n'est pas celui que vous ont été à l'origine de problèmes. Beaucoup de langues n'ont pas d' void* et n'ont aucun problème avec ça, par exemple.

Une autre utilisation légitime

Lors de l'impression de pointeur d'adresses avec des fonctions comme l' printf le pointeur doit avoir void* type et, par conséquent, vous pouvez avoir besoin d'une fonte d' void*

7voto

skypjack Points 5516

Oui, c'est aussi utile que toute autre chose dans la langue.
Comme un exemple, vous pouvez l'utiliser pour effacer le type d'une classe que vous êtes en mesure de statiquement en fonte pour le type de droit lorsque cela est nécessaire, afin de disposer d'un minimum et d'interface flexible.

Dans cette réponse, il est un exemple de l'utilisation qui devrait vous donner une idée.
Je fais un copier-coller ci-dessous par souci de clarté:

class Dispatcher {
    Dispatcher() { }

    template<class C, void(C::*M)() = C::receive>
    static void invoke(void *instance) {
        (static_cast<C*>(instance)->*M)();
    }

public:
    template<class C, void(C::*M)() = &C::receive>
    static Dispatcher create(C *instance) {
        Dispatcher d;
        d.fn = &invoke<C, M>;
        d.instance = instance;
        return d;
    }

    void operator()() {
        (fn)(instance);
    }

private:
    using Fn = void(*)(void *);
    Fn fn;
    void *instance;
};

Évidemment, ce n'est qu'un tas d'utilisations de l' void*.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X