Pourquoi les pointeurs ne sont-ils pas recommandés lors du codage en C ++?

45

J'ai lu quelque part que, lors de l'utilisation de C ++, il est recommandé de ne pas utiliser de pointeur. Pourquoi les pointeurs sont-ils une si mauvaise idée lorsque vous utilisez C ++? Pour les programmeurs C habitués à utiliser des pointeurs, quelle est la meilleure alternative et approche en C ++?

Joshua Partogi
la source
40
S'il vous plaît lien vers "quelque part". Le contexte pourrait être très pertinent.
1
Espérons que cette question vous sera utile.
Garet Claborn
La plupart de ces réponses font référence à l’évitement des fuites de mémoire comme raison principale. Je ne me souviens pas de la dernière fois où l'une de nos applications avait un problème de fuite de mémoire malgré l'utilisation de pointeurs. Si vous avez des problèmes de fuite de mémoire, vous n’utilisez pas les bons outils ou vous ne savez pas ce que vous faites. La plupart des environnements de développement disposent d'un moyen de vérifier automatiquement les fuites intégrées. Je pense que les problèmes de fuites de mémoire sont beaucoup plus difficiles à localiser dans les langages ramassés, car leur occurrence est beaucoup plus subtile et vous avez souvent besoin d'un outil tiers pour localiser le coupable. .
Dunk
1
Ajoutant au commentaire de @Dunk, les éboueurs intégrés dans les langages de niveau supérieur parfois ne fonctionnent tout simplement pas correctement. Le ramasse-miettes d'ActionScript 3 ne le fait pas, par exemple. Il y a actuellement un bogue qui concerne les NetConnectioninstances qui se déconnectent du serveur ( stackoverflow.com/questions/14780456/… ), ainsi qu'un problème lié à la présence de plusieurs objets dans un programme qu'il refusera spécifiquement de collecter. ...
Panzercrisis
... ( adobe.com/devnet/actionscript/learning/as3-fundamentals/… - recherchez GCRoots are never garbage collected.et le paragraphe commençant par The MMgc is considered a conservative collector for mark/sweep.). Techniquement, il s'agit d'un problème dans Adobe Virtual Machine 2, pas AS3, mais lorsque vous rencontrez des problèmes de ce type dans les langages de niveau supérieur, dans lesquels la récupération de place est essentiellement intégrée, vous n'avez souvent aucun moyen véritable de déboguer dans le langage. ces questions complètement hors du programme. ...
Panzercrisis

Réponses:

58

Je pense qu'ils signifient que vous devriez utiliser des pointeurs intelligents au lieu des pointeurs normaux.

En informatique, un pointeur intelligent est un type de données abstrait qui simule un pointeur tout en offrant des fonctionnalités supplémentaires, telles que le garbage collection automatique ou la vérification des limites. Ces fonctionnalités supplémentaires ont pour but de réduire les erreurs causées par l’utilisation abusive de pointeurs tout en préservant l’efficacité. Les pointeurs intelligents gardent généralement une trace des objets vers lesquels ils pointent à des fins de gestion de la mémoire.

La mauvaise utilisation des pointeurs est une source majeure de bogues: l’affectation constante, la désallocation et le référencement qui doivent être effectués par un programme écrit à l’aide de pointeurs présentent le risque de fuites de mémoire. Les pointeurs intelligents tentent d’empêcher les fuites de mémoire en rendant automatique le désallocation des ressources: lorsque le pointeur (ou le dernier d’une série de pointeurs) sur un objet est détruit, par exemple parce qu’il sort du champ, l’objet pointé est également détruit.

En C ++, l'accent est mis sur la récupération de place et la prévention des fuites de mémoire (pour n'en nommer que deux). Les pointeurs sont une partie fondamentale du langage, il est donc pratiquement impossible de les utiliser, sauf dans les programmes les plus divers.

jmq
la source
22
typiquement sa collecte non strictement ordures au sens classique du terme, plus de comptage de références. Au moins dans le ptr intelligent, je suis habitué à ([boost | std] :: shared_ptr)
Doug T.
3
Cette réponse est très limitée au pointeur intelligent, qui n’est qu’un aspect mineur du problème. De plus, les pointeurs intelligents ne sont pas un garbage collection.
deadalnix
3
Aussi RAII en général.
Klaim
3
Non, ce n'est pas ce que ça veut dire. Il est seulement un aspect, et non le plus important.
Konrad Rudolph
Je pense que les pointeurs intelligents sont l’aspect le plus important, mais je conviens qu’il en existe beaucoup d’autres.
DeadMG
97

Étant donné que c'est moi qui ai publié la polémique «N'utilisez pas d'indices fictifs», j'estime que je devrais faire un commentaire ici.

Tout d'abord, en tant que polémique, cela représente évidemment un point de vue extrême. Il existe certainement des utilisations légitimes des pointeurs (bruts). Mais moi (et de nombreux programmeurs professionnels C ++), maintenons que ces cas sont extrêmement rares. Mais ce que nous voulons vraiment dire est le suivant:

Première:

Les pointeurs bruts ne doivent en aucun cas posséder de mémoire.

Ici, «propre mémoire» signifie essentiellement que deletece pointeur est appelé à un moment donné (mais que c'est plus général que cela). Cette déclaration peut être considérée comme absolue. La seule exception concerne l’implémentation de votre propre pointeur intelligent (ou d’une autre stratégie de gestion de la mémoire). Et même là, vous devriez normalement toujours utiliser un pointeur intelligent à bas niveau.

La raison en est assez simple: les pointeurs bruts qui possèdent leur propre mémoire introduisent une source d'erreur. Et ces erreurs sont prolifiques dans les logiciels existants: fuites de mémoire et double suppression - l'une des conséquences directes de la propriété de ressources peu claire (mais allant dans le sens opposé).

Ce problème peut être entièrement éliminé, pratiquement sans frais, en utilisant simplement des pointeurs intelligents au lieu de pointeurs bruts (attention: cela exige toujours de réfléchir, bien sûr; des pointeurs partagés peuvent conduire à des cycles et donc à des fuites de mémoire, mais cela est facile. évitable).

Seconde:

La plupart des utilisations de pointeurs en C ++ sont inutiles.

Contrairement à d'autres langages, C ++ supporte très bien la sémantique des valeurs et n'a tout simplement pas besoin de l'indirection des pointeurs. Cela n’a pas été immédiatement réalisé - historiquement, le C ++ a été inventé pour faciliter l’orientation facile des objets en C et s’appuie fortement sur la construction de graphes d’objets reliés entre eux par des pointeurs. Mais dans le C ++ moderne, ce paradigme est rarement le meilleur choix et les idiomes modernes du C ++ n’ont souvent pas besoin de pointeur . Ils opèrent sur des valeurs plutôt que des pointeurs.

Malheureusement, ce message n’a toujours pas été compris dans la plupart des utilisateurs C ++. En conséquence, la plupart du code C ++ écrit est toujours jonché de pointeurs superflus qui le rendent complexe, lent et défectueux / non fiable.

Pour ceux qui connaissent le C ++ moderne, il est clair que vous avez très rarement besoin de pointeurs (intelligents ou bruts; sauf lorsque vous les utilisez comme itérateurs). Le code résultant est plus court, moins complexe, plus lisible, souvent plus efficace et plus fiable.

Konrad Rudolph
la source
5
Soupir ... cela devrait vraiment être la réponse avec plus de 30 votes positifs ... surtout pour le deuxième point. Les pointeurs ne sont que rarement nécessaires en C ++ moderne.
Charles Salvia
1
qu'en est-il par exemple. L'objet Gui possède un tas d'objets doc. Il a ces deux types de pointeurs afin que la classe puisse être déclarée en aval (évite les recompilations) et que l'objet puisse être initialisé lors de la création (avec new) plutôt que d'être créé sur la pile dans un état vide puis archivé plus tard? Cela semble une utilisation parfaitement valide des pointeurs - tous les objets encapsulés ne devraient-ils pas être sur le tas?
Martin Beckett
4
Les objets de l'interface graphique @Martin sont l'un des cas où les graphes d'objet de pointeur constituent la meilleure solution. Mais l'édit contre les pointeurs bruts possédant la mémoire est toujours valable. Utilisez des pointeurs partagés ou développez un modèle de propriété approprié et n’avez que des relations faibles (= non propriétaires) entre les contrôles via des pointeurs bruts.
Konrad Rudolph
1
@ VF1 std::unique_ptr. Aussi pourquoi pas ptr_vec? Mais généralement, un vecteur de valeur avec sera toujours échanger plus rapidement (surtout avec la sémantique de déplacement).
Konrad Rudolph
1
@gaazkam Personne ne vous a forcé à utiliser uniquement des conteneurs standard. Boost par exemple a une implémentation de carte avec support pour les types incomplets. Une autre solution consiste à utiliser le type effacement; boost::variantavec recursive_wrapperest probablement ma solution préférée pour représenter un DAG.
Konrad Rudolph
15

Tout simplement parce que vous avez à votre disposition des abstractions qui cachent les aspects les plus instinctifs de l’utilisation de pointeurs, tels que l’accès à la mémoire brute et le nettoyage après vos allocations. Avec les pointeurs intelligents, les classes de conteneur et les modèles de conception tels que RAII, la nécessité d'utiliser des pointeurs bruts est réduite. Cela dit, comme pour toute abstraction, vous devez comprendre comment ils fonctionnent avant de les dépasser.

Ed S.
la source
11

Relativement simplement, la mentalité C est "Vous avez un problème? Utilisez un pointeur". Vous pouvez le voir dans les chaînes de caractères C, les pointeurs de fonction, les pointeurs en tant qu'itérateurs, le pointeur à l'autre, le pointeur vide, même dans les débuts de C ++ avec des pointeurs membres.

Mais en C ++, vous pouvez utiliser des valeurs pour plusieurs ou toutes ces tâches. Besoin d'une abstraction de fonction? std::function. C'est une valeur qui est une fonction. std::string? C'est une valeur, c'est une chaîne. Vous pouvez voir des approches similaires partout dans C ++. Cela facilite grandement l’analyse du code, tant pour les utilisateurs que pour les compilateurs.

DeadMG
la source
En C ++: Vous avez un problème? Utilisez un pointeur. Maintenant vous avez 2 problèmes ...
Daniel Zazula
10

Une des raisons est l'application trop large des pointeurs. Ils peuvent être utilisés pour les itérations sur les conteneurs, pour éviter de copier des objets volumineux lors du passage à une fonction, pour une gestion de la durée de vie non triviale, pour accéder à des emplacements aléatoires en mémoire, etc. immédiatement indépendamment de l'intention.

La sélection d'un outil dans le but précis rend le code plus simple et l'intention plus visible - itérateurs pour les itérations, pointeurs intelligents pour la gestion de la durée de vie, etc.

maxim1000
la source
3

Outre les raisons déjà énumérées, il en existe une évidente: de meilleures optimisations. L'analyse de repliement est beaucoup trop compliquée en présence d'un arithmétique à pointeur, alors que les références suggèrent l'optimiseur, de sorte qu'une analyse de repliement beaucoup plus profonde est possible si seules les références sont utilisées.

SK-logic
la source
2

Outre le risque de fuite de mémoire indiqué par @jmquigley, l'arithmétique de pointeur et d'arithmétique de pointeur peut être considérée comme problématique, car les pointeurs peuvent pointer partout dans la mémoire, causant des "bogues difficiles à trouver" et des "vulnérabilités en matière de sécurité".

C'est pourquoi ils ont été presque abandonnés en C # et Java.

k3b
la source
Attendez-vous à ce qu'ils ne soient pas "abendonnés" en C #. Cette réponse est médiocre, son orthographe est horrible et sa déclaration inexacte.
Ramhound
1
Ils ont été presque abandonnés. Je m'excuse de ne pas être un locuteur natif.
k3b
1
Hé, on peut aider avec l'orthographe. Vouliez-vous dire attendre ou excepté?
DeveloperDon
1
Presque abandonné en C #, vous pouvez toujours activer le pointeur en spécifiant le unsafemot
linquize
-1

C ++ prend en charge la plupart des fonctions C , ainsi que des objets et des classes. C avait déjà des pointeurs et d’autres choses.

Les pointeurs sont une technique très utile, qui peut être combinée avec Orientation objet, et C ++ les prend en charge. Mais, cette technique est difficile à enseigner et à comprendre, et il est très facile de provoquer des erreurs indésirables.

Beaucoup de nouveaux langages de programmation prétendent ne pas utiliser de pointeurs avec des objets, tels que Java, .NET, Delphi, Vala, PHP, Scala. Mais, les pointeurs sont toujours utilisés, "dans les coulisses". Ces techniques de "pointeur caché" sont appelées "références".

Quoi qu'il en soit, je considère le (s) pointeur (s) comme un motif de programmation, comme un moyen valable de résoudre certains problèmes, comme le fait la programmation orientée objet .

D'autres développeurs peuvent avoir un avis différent. Mais, je suggère aux étudiants et aux programmeurs d'apprendre à:

(1) Utilisez des pointeurs sans objets

(2) objets sans pointeurs

(3) pointeurs explicites vers des objets

(4) pointeurs "cachés" vers les objets ( référence AKA ) ;-)

Dans cet ordre.

Même si c'est difficile à enseigner et difficile à apprendre. Object Pascal (Delphi, FreePascal, autres) et C++(pas Java ou C #) peuvent être utilisés pour ces objectifs.

Et, plus tard, les programmeurs débutants peuvent utiliser des langages de programmation tels que: Java, C #, PHP orienté objet, etc.

Umlcat
la source
19
C ++ est bien plus que le "C with Classes" pour lequel il a commencé.
David Thornley
Pourquoi encapsulez-vous C ++ et C dans des citations aériennes? Et "caché", "références" et tout le reste? Êtes-vous un "vendeur" et ne participez pas à la "programmation"?
phresnel
Je devrais les mettre en gras. Les citations peuvent être utilisées pour mettre en évidence mais aussi le contraire
umlcat
-6

En parlant de VC6, lorsque vous transformez un pointeur d'une classe (que vous instanciez) en une variable (par exemple, DWORD), même si ce pointeur est local, vous pouvez accéder à la classe via toutes les fonctions utilisant le même segment de mémoire. La classe instanciée est définie comme locale mais en réalité, elle ne l’est pas. Autant que je sache, toute adresse de variable, structure ou classe de tas est unique tout au long de la vie de la classe d’accueil.

Exemple:

class MyClass1 {
    public:
        void A (void);
        void B (void);
        void C (void);
    private:
        DWORD dwclass;
};

class MyClass2 {
    public:
        int C (int i);
};

void MyClass1::A (void) {
    MyClass2 *myclass= new MyClass2;
    dwclass=(DWORD)myclass;
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    int i = myclass->C(0); // or int i=((MyClass2 *)dwclass)->C(0);
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    delete myclass;
}

EDIT Thats une très petite partie du code original. La classe CSRecodset est uniquement une classe de transtypage de CXdbRecordset, où se trouve tout le code réel. Ce faisant, je peux laisser l’utilisateur profiter de ce que j’ai écrit sans perdre mes droits. Je ne prétends pas démontrer que mon moteur de base de données est professionnel, mais cela fonctionne vraiment.

//-------------------------------------
class CSRecordSet : public CSObject
//-------------------------------------
{
public:
    CSRecordSet();
    virtual ~CSRecordSet();
    // Constructor
    bool Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef);
    //Open, find, close
    int OpenRst(bool bReadBlanks=0,bool bCheckLastSql=0,bool bForceLoad=0,bool bMessage=1);     // for a given SQL
    int FindRecord(bool bNext);         // for a given SQL
    // TABLE must be ordered by the same fields that will be seek
    bool SeekRecord(int nFieldIndex, char *key, int length=0);  // CRT bsearch
    bool SeekRecord(int nFieldIndex, long key);     
    bool SeekRecord(int nFieldIndex, double key, int decimals);     
    bool SeekRecord(XSEK *SEK);     
    bool DeleteRecord(void);
    bool Close(void);
    // Record Position:
    bool IsEOF(void);           // pointer out of bound
    bool IsLAST(void);          // TRUE if last record
    bool IsBOF(void);           // pointer out of bound
    bool IsOpen(void);
    bool Move(long lRows);      // returns FALSE if out of bound
    void MoveNextNotEof(void);  // eof is tested
    void MoveNext(void);        // eof is not tested
    void MovePrev(void);        // bof is tested
    void MoveLast(void);
    void MoveFirst(void);
    void SetAbsolutePosition(long lRows);
    long GetAbsolutePosition(void);
    void GoToLast(void); // Restore position after a Filter
    // Table info
    long GetRecordCount(void);
    int GetRstTableNumber(void);
    int GetRecordLength(void); //includes stamp (sizeof char)
    int GetTableType(void);
    // Field info
    int GetFieldCount(void);
    void GetFieldName(int nFieldIndex, char *pbuffer);
    int GetFieldIndex(const char *sFieldName);
    int GetFieldSize(int nFieldIndex);
    int GetFieldDGSize(int nFieldIndex); // String size (i.e. dg_Boolean)
    long GetRecordID(void);
    int GetStandardFieldCount(void);
    bool IsMemoFileTable(void);
    bool IsNumberField(int nFieldIndex);
    int GetFieldType(int nFieldIndex);
    // Read Field value
    bool GetFieldValue(int nFieldIndex, XdbVar& var);
    bool GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer);
    char *GetMemoField(int nMemoFieldIndex, char *pbuffer, int buf_size);
    bool GetBinaryField(unsigned char *buffer,long *buf_size);
    // Write Field value
    void Edit(void); // required
    bool SetFieldValue(int nFieldIndex, XdbVar& var);
    bool SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer);
    bool Update(void); // required
    // pointer to the same lpSql
    LPXSQL GetSQL(void);
};

//---------------------------------------------------
CSRecordSet::CSRecordSet(){
//---------------------------------------------------
    pClass |= (CS_bAttach);
}
CSRecordSet::~CSRecordSet(){
    if(pObject) delete (CXdbRecordset*)pObject;
}
bool CSRecordSet::Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef){
    CXdbQueryDef *qr=(CXdbQueryDef*)pQueryDef->GetObject();
    CXdbTables *db=(CXdbTables*)pDataBase->GetObject();
    CXdbRecordset *rst = new CXdbRecordset(db,qr);
    if(rst==NULL) return 0;
    pObject = (unsigned long) rst;
    return 1;
}
bool CSRecordSet::Close(void){
    return ((CXdbRecordset*)pObject)->Close();
}
int CSRecordSet::OpenRst(bool bReadBlanks,bool bCheckLastSql,bool bForceLoad, bool bMessage){
    unsigned long dw=0L;
    if(bReadBlanks) dw|=SQL_bReadBlanks;
    if(bCheckLastSql) dw|=SQL_bCheckLastSql;
    if(bMessage) dw|=SQL_bRstMessage;
    if(bForceLoad) dw|=SQL_bForceLoad;

    return ((CXdbRecordset*)pObject)->OpenEx(dw);
}
int CSRecordSet::FindRecord(bool bNext){
    return ((CXdbRecordset*)pObject)->FindRecordEx(bNext);
}
bool CSRecordSet::DeleteRecord(void){
    return ((CXdbRecordset*)pObject)->DeleteEx();
}
bool CSRecordSet::IsEOF(void){
    return ((CXdbRecordset*)pObject)->IsEOF();
}
bool CSRecordSet::IsLAST(void){
    return ((CXdbRecordset*)pObject)->IsLAST();
}
bool CSRecordSet::IsBOF(void){
    return ((CXdbRecordset*)pObject)->IsBOF();
}
bool CSRecordSet::IsOpen(void){
    return ((CXdbRecordset*)pObject)->IsOpen();
}
bool CSRecordSet::Move(long lRows){
    return ((CXdbRecordset*)pObject)->MoveEx(lRows);
}
void CSRecordSet::MoveNextNotEof(void){
    ((CXdbRecordset*)pObject)->MoveNextNotEof();
}
void CSRecordSet::MoveNext(void){
    ((CXdbRecordset*)pObject)->MoveNext();
}
void CSRecordSet::MovePrev(void){
    ((CXdbRecordset*)pObject)->MovePrev();
}
void CSRecordSet::MoveLast(void){
    ((CXdbRecordset*)pObject)->MoveLast();
}
void CSRecordSet::MoveFirst(void){
    ((CXdbRecordset*)pObject)->MoveFirst();
}
void CSRecordSet::SetAbsolutePosition(long lRows){
    ((CXdbRecordset*)pObject)->SetAbsolutePosition(lRows);
}
long CSRecordSet::GetAbsolutePosition(void){
    return ((CXdbRecordset*)pObject)->m_AbsolutePosition;
}
long CSRecordSet::GetRecordCount(void){
    return ((CXdbRecordset*)pObject)->GetRecordCount();
}
int CSRecordSet::GetFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetFieldCount();
}
int CSRecordSet::GetRstTableNumber(void){
    return ((CXdbRecordset*)pObject)->GetRstTableNumber();
}
void CSRecordSet::GetFieldName(int nFieldIndex, char *pbuffer){
    ((CXdbRecordset*)pObject)->GetFieldName(nFieldIndex,pbuffer);
}
int CSRecordSet::GetFieldIndex(const char *sFieldName){
    return ((CXdbRecordset*)pObject)->GetFieldIndex(sFieldName);
}
bool CSRecordSet::IsMemoFileTable(void){
    return ((CXdbRecordset*)pObject)->IsMemoFileTable();
}
bool CSRecordSet::IsNumberField(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->IsNumberField(nFieldIndex);
}
bool CSRecordSet::GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer){
    return ((CXdbRecordset*)pObject)->GetFieldValueIntoBuffer(nFieldIndex,pbuffer);
}
void CSRecordSet::Edit(void){
    ((CXdbRecordset*)pObject)->Edit();
}
bool CSRecordSet::Update(void){
    return ((CXdbRecordset*)pObject)->Update();
}
bool CSRecordSet::SetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->SetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer){
    return ((CXdbRecordset*)pObject)->SetFieldValueFromBuffer(nFieldIndex,pbuffer);
}
bool CSRecordSet::GetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->GetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SeekRecord(XSEK *SEK){
    return ((CXdbRecordset*)pObject)->TableSeek(SEK);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,char *key, int length){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,key,length);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,long i){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,i);
}
bool CSRecordSet::SeekRecord(int nFieldIndex, double d, int decimals)
{
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,d,decimals);
}
int CSRecordSet::GetRecordLength(void){
    return ((CXdbRecordset*)pObject)->GetRecordLength();
}
char *CSRecordSet::GetMemoField(int nMemoFieldIndex,char *pbuffer, int BUFFER_SIZE){
    return ((CXdbRecordset*)pObject)->GetMemoField(nMemoFieldIndex,pbuffer,BUFFER_SIZE);
}
bool CSRecordSet::GetBinaryField(unsigned char *buffer,long *buf_size){
    return ((CXdbRecordset*)pObject)->GetBinaryField(buffer,buf_size);
}
LPXSQL CSRecordSet::GetSQL(void){
    return ((CXdbRecordset*)pObject)->GetSQL();
}
void CSRecordSet::GoToLast(void){
    ((CXdbRecordset*)pObject)->GoToLast();
}
long CSRecordSet::GetRecordID(void){
    return ((CXdbRecordset*)pObject)->GetRecordID();
}
int CSRecordSet::GetStandardFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetStandardFieldCount();
}
int CSRecordSet::GetTableType(void){
    return ((CXdbRecordset*)pObject)->GetTableType();
}
int CSRecordSet::GetFieldType(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldType(nFieldIndex);
}
int CSRecordSet::GetFieldDGSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldDGSize(nFieldIndex);
}
int CSRecordSet::GetFieldSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldSize(nFieldIndex);
}

EDIT: demandé par DeadMG:

void nimportequoidumomentquecaroule(void) {

    short i = -4;
    unsigned short j=(unsigned short)i;

}
Salvador
la source
1
Certains codes pourraient améliorer considérablement cette description pour illustrer ce que vous décrivez. J'ai l'impression que cela se rapportait à la question initiale, mais si vous nous préveniez d'un danger dans ce scénario, cela aiderait à préciser le sujet de l'interrogateur.
DeveloperDon
1
Ce cast DWORDest abusif et peut-être incorrect (DWORD n'est pas nécessairement assez large pour contenir un pointeur). Si vous avez besoin d'un pointeur non typé, utilisez void*- mais lorsque vous pensez avoir besoin de cela en C ++, vous rencontrez souvent un problème de conception dans votre code que vous devez corriger.
Mat
Salvador, je pense que vous essayez de dire quelque chose à propos de VC6 et de la manière dont il gère les pointeurs de manière inhabituelle et inattendue. L'exemple pourrait tirer parti des commentaires, et si vous voyez des avertissements du compilateur, ils pourraient être instructifs pour relier votre réponse à la question.
DeveloperDon
@Mat Cet exemple concerne un système d'exploitation 32 bits et le compilateur VC6 ++.
Salvador
6
Parler de mauvais code dans un compilateur absolument ancien? Non merci.
DeadMG