Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++ > Langage
Langage Langage C++, Programmation Orientée Objet, Templates, etc. Avant de poster : FAQ C++
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 16/02/2013, 15h25   #1
vikki
Membre confirmé
 
Avatar de vikki
 
Inscription : mai 2007
Messages : 292
Détails du profil
Informations personnelles :
Âge : 28
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2007
Messages : 292
Points : 266
Points : 266
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.
vikki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2013, 15h51   #2
Bousk
Modérateur
 
Homme Cyrille
Network programmer
Inscription : juin 2010
Messages : 1 551
Détails du profil
Informations personnelles :
Nom : Homme Cyrille
Âge : 25
Localisation : France

Informations professionnelles :
Activité : Network programmer

Informations forums :
Inscription : juin 2010
Messages : 1 551
Points : 4 099
Points : 4 099
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.
Bousk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 16/02/2013, 17h55   #3
vikki
Membre confirmé
 
Avatar de vikki
 
Inscription : mai 2007
Messages : 292
Détails du profil
Informations personnelles :
Âge : 28
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations forums :
Inscription : mai 2007
Messages : 292
Points : 266
Points : 266
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).
vikki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/02/2013, 18h21   #4
germinolegrand
Rédacteur/Modérateur
 
Avatar de germinolegrand
 
Homme Germino Legrand
Développeur de jeux vidéo
Inscription : octobre 2010
Messages : 370
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 : 370
Points : 1 873
Points : 1 873
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.
germinolegrand est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/02/2013, 16h05   #5
koala01
Modérateur
 
Avatar de koala01
 
Philippe Dunski
Inscription : octobre 2004
Messages : 8 625
Détails du profil
Informations personnelles :
Nom : Philippe Dunski
Âge : 41

Informations forums :
Inscription : octobre 2004
Messages : 8 625
Points : 13 342
Points : 13 342
Envoyer un message via MSN à koala01 Envoyer un message via Skype™ à koala01
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
Citation:
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
je ne répondrai à aucune question technique par E-mail, message visiteur ou message privé
Vous avez obtenu votre réponse pensez au bouton en bas de page
koala01 est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 12h00.


 
 
 
 
Partenaires

Hébergement Web