Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 5 sur 5
  1. #1
    Membre confirmé Avatar de vikki
    Profil pro
    Inscrit en
    mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 29
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : mai 2007
    Messages : 292
    Points : 249
    Points
    249

    Par défaut reinterpret_cast de collection de pointeur

    Bonjour à tous,

    Je me demandais s'il était légal (dans le sens ayant un comportement prédictif) de caster brutalement un std::vector de pointeur vers un std::vector d'un autre type de pointeur.

    Concrètement cela donne:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struct test {
       int var;
    };
     
    std::vector<void*> collection;
     
    /*
    .
    .
    fill collection
    .
    .
    */
     
    std::vector<test*> res = *reinterpret_cast< const std::vector<test*> * >(&collection);
    On suppose dans ce cas que les pointeurs dans 'collection' pointent tous bien vers des instances de type 'test'. Cela fonctionne parfaitement sous Visual et semble d'ailleurs deux fois plus rapide qu'une copie via boucle for. Par contre, cela ressemble furieusement à une bombe à retardement prête à me sauter à la tête.

    Je n'arrive pas à trouver une réponse claire sur le net à part que cette méthode est moche et à éviter.

  2. #2
    Modérateur

    Homme Profil pro Cyrille
    Network programmer
    Inscrit en
    juin 2010
    Messages
    2 078
    Détails du profil
    Informations personnelles :
    Nom : Homme Cyrille
    Âge : 27
    Localisation : France

    Informations professionnelles :
    Activité : Network programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 2 078
    Points : 4 902
    Points
    4 902

    Par défaut

    Bonjour,

    je pense que c'est au mieux dangeureux.
    vector est un type complexe, caster chaque élément est à la limite explicable, mais le vector entier pas vraiment.
    Si vraiment je devais réaliser un tel cast, je le casterais probablement vers un tableau et non un vector:
    Code :
    test** = reinterpret_cast<test**>(&(vec[0]));
    Pour passer d'un élément à l'autre, un peu d'arithmétique des pointeurs.

  3. #3
    Membre confirmé Avatar de vikki
    Profil pro
    Inscrit en
    mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 29
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : mai 2007
    Messages : 292
    Points : 249
    Points
    249

    Par défaut

    C'est certain que cela semble douteux. Cependant, si la class vector n'est pas spécialisée pour les pointeurs considérés, j'ai du mal à voir où est le danger (à part pour les cast entre pointeurs eux mêmes en cas d’héritage multiple).

  4. #4
    Expert Confirmé

    Avatar de germinolegrand
    Homme Profil pro Germino Legrand
    Développeur de jeux vidéo
    Inscrit en
    octobre 2010
    Messages
    731
    Détails du profil
    Informations personnelles :
    Nom : Homme Germino Legrand
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : octobre 2010
    Messages : 731
    Points : 3 938
    Points
    3 938

    Par défaut

    Si tu veux copier le tableau, je te conseille memcpy.
    C++03 :
    Code :
    1
    2
    3
    4
    5
     
    std::vector<void*> first;
     
    std::vector<T*> sec(first.size());
    memcpy(&sec[0], &first[0], first.size()*sizeof(void*));
    C++11 :
    Code :
    1
    2
    3
    4
    5
    6
     
    std::vector<void*> first;
     
    std::vector<T*> sec;
    sec.resize(first.size());
    memcpy(sec.data(), first.data(), first.size()*sizeof(void*));
    Choisis un travail que tu aimes et tu n'auras pas à travailler un seul jour de ta vie.

    N'oubliez pas de marquer votre sujet comme et de mettre des aux messages apportant un plus à votre discussion.

    Si vous souhaitez participer à la rubrique C++, ne me contactez plus !

  5. #5
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 688
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 688
    Points : 15 747
    Points
    15 747

    Par défaut

    Salut,

    Pour répondre à la première question, oui, c'est légal dans le sens où c'est l'utilisation pour laquelle est prévue reinterpret_cast.

    Il faut cependant bien comprendre ce que fait reinterpret_cast pour être sur de ne pas risquer de "tout faire pêter" :

    En effet, cela a un comportement tout à fait similaire au cast "C style" brutal et barbare, dans le sens où cela indique au compilateur quelque chose comme
    Je sais que tu connais telle donnée comme étant de tel type, mais je te demande de me faire confiance et de la considérer comme s'il s'agissait de tel autre type
    Le compilateur va donc te faire une confiance aveugle et considérer la variable comme étant du type que tu lui a indiqué, sans se poser la moindre question

    Comme tu l'as toi même si bien fait remarquer, cela revient à armer une bombe à retardement car, si tu te trompes de type, il est très difficile de prévoir le résultat que tu obtiendras

    De plus, il faut se méfier avec la classe std::vector dans le sens où elle maintient le nombre d'éléments qu'elle contient ainsi que le nombre d'éléments au delà duquel elle devra agrandir la taille du tableau.

    Le réinterpret_cast ne va en aucun cas forcer la classe vector à recalculer ces valeurs pour les adapter à la nouvelle taille des éléments.

    Tu risques donc de tenter d'accéder à des éléments "hors limites" si tu transtype ton vector d'un type en un vector d'un type de taille supérieure (par exemple, un std::vector<int> en std::vector<double>).

    Par chance, la taille d'un pointeur est clairement définie pour un compilateur donné sur une architecture donnée, et tu retardes donc ce risque si tu travailles sur un std::vector qui manipule des pointeurs au moment où tu essayeras d'accéder à l'élément pointé par le pointeur (car sizeof(int) est différent de sizeof(double)), dans le sens où le tableau sous jascent de std::vector gardera la même taille qu'il s'agisse de pointeurs sur void, sur int ou sur double.

    Bref, tu l'auras compris: la méthode est légale, mais très moche et à éviter autant que faire se peut

    De prime abord, je te conseillerais de limiter l'utilisation de cette technique aux cas où tu n'as vraiment pas le choix: lorsqu'il s'agit, par exemple, de t'interfacer avec une fonction C qui prend un pointeur de pointeurs sur void ou cas similaires

    Tu utiliserais alors sans doute quelque chose comme
    Code :
    laFonctionC(reinterpret_cast<void**>(&myVector[0]);
    Dans tous les autres cas, tu as franchement largement intérêt à utiliser ton vector comme ce qu'il est: une collection d'objet d'un type clairement défini
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •