2011-09-05 3 views
3

Chaque fois que je tente de compiler mon code, j'obtiens l'erreur:Argument passage par référence à un problème de pointeur

ne peut pas convertir le paramètre 1 de « int * » pour « int * & »

Il est le code de test à la recherche comme ce:

void set (int *&val){ 
    *val = 10; 
} 

int main(){ 
    int myVal; 
    int *pMyVal = new int; 
    set(&myVal); // <- this cause trouble 
    set(pMyVal); // <- however this doesn't 
} 

Je voudrais appeler cette fonction en un seul coup sans créer de pointeur quelque part que pour une raison de le passer. Et comme les pointeurs n'ont pas de constructeur, quelque chose comme ça ne peut pas être fait. set(int*(&myVal));. Y at-il un autre moyen de passer le pointeur par référence sans avoir besoin de créer une variable temporaire? En passant, je sais pourquoi le code ne parvient pas à compiler (je ne fais que passer l'adresse qui est peut-être int et pointeur réel). La question est de savoir comment cela peut être fait autrement.

+0

Si vous ne voulez pas créer un pointeur, pourquoi avez-vous besoin de la fonction de prendre un pointeur (par référence)? Pourquoi pas 'set (int & v) {v = 10;}'? – Beta

+0

Parce que ma classe stocke la valeur, mais cette valeur est ensuite passée comme pointeur vers une autre classe qui stocke ce pointeur. Ce pointeur doit être défini par référence à l'argument pointeur dans la fonction qui le fait, car sinon le pointeur passé ne pointe pas vraiment vers la valeur, mais vers sa copie. Et avant de paramétrer ce pointeur je ne veux pas créer de pointeur temporaire juste pour pouvoir le passer .. C'est pourquoi je n'ai pas introduit de problème réel, mais seulement celui qui me ressemble et qui est beaucoup plus facile. – Raven

Répondre

10

Une référence à non-const ne peut pas se lier à une valeur. Le résultat de l'opérateur & est un rvalue. Jetez un oeil à the difference between lvalues and rvalues ou lisez a good C++ book.

De plus, dans votre contexte, vous n'avez pas besoin de passer par référence. Ce qui suit est également OK:

void set (int *val){ 
    *val = 10; 
} 

La référence serait nécessaire si vous deviez faire quelque chose comme ceci;

void set (int*& val){ 
    val = new int; //notice, you change the value of val, not *val 
    *val = 10; 
} 
+0

donc 'int * const & p' fait référence au pointeur constant vers integer, et donc il peut être assigné rvalue, non? – Raven

+2

@Raven: Oui, c'est correct. Mais pas besoin de passer les types intégrés en référence à const. C'est moins efficace que de passer en valeur. Pour les types définis par l'utilisateur, il est préférable de passer par référence à const –

2

&myval est une rvalue (de type int*), parce qu'il est temporaire. C'est un pointeur, mais vous ne pouvez pas le modifier, car il vient d'être créé à la volée. Votre fonction set requiert cependant une référence non-const, donc vous ne pouvez pas la passer temporairement.

Par contre, pMyVal est une variable nommée, donc une lvalue, donc elle peut être passée comme une référence non constante.

+0

Je dirais que '& myval' est de type' int * const & '. – starblue

+0

Désolé, mais cela est incorrect et trompeur à bien des égards. Pour un, 'const int * &' est une "référence à un pointeur vers const int", pas une "référence au pointeur constant". Deuxièmement, il y a une distinction entre les références à const et à rvalues ​​(les rvalues ​​_don't_ ont le type 'const T &'). Troisièmement, un objet n'a pas besoin d'être nommé pour être une lvalue. – jpalecek

+0

@starblue: Oui, mon erreur. Corrigé, et merci! –

0

Le problème est, int*&val ne peut être passé qu'une lvalue, ce qui n'est pas le résultat de & myVal. En changeant la signature à void set(int* const& val), cela indique au compilateur que vous n'allez pas changer la valeur du pointeur.

Cependant, vous ne le feriez normalement pas, uniquement parce que si vous ne modifiez pas la valeur du pointeur, le passage du pointeur par valeur est le moyen le plus simple de transmettre la valeur. Et si vous voulez changer la valeur du pointeur, vous devez créer un temporaire pour recevoir le résultat.

0

Vous pouvez voir le code exemple suivant:

#include <iostream> 
using namespace std; 

void change(int*& ptr) { 
    cout << endl; 
    cout << "==================change(int*& ptr)====================" << endl; 
    cout << " &ptr = " << &ptr << endl; 
    cout << " ptr = " << ptr << endl; 
    cout << "=======================================================" << endl; 
    cout << endl; 
    *ptr *= *ptr; 
} 

int main(void) { 
    int* ptrNumber = new int(10); 

    cout << endl; 
    cout << "&ptrNumber = " << &ptrNumber << endl; 
    cout << "ptrNumber = " << ptrNumber << endl; 
    cout << ">>> *ptrNumber = " << *ptrNumber << endl; 
    change(ptrNumber); 
    cout << "<<< *ptrNumber = " << *ptrNumber << endl; 
} 

J'ai installé et utilisé Cygwin g ++ pour compiler le code source ci-dessus, le fichier binaire est out_pointer.exe. Exécution de out_pointer.exe, la sortie est comme suit:

$ ./out_pointer.exe 

&ptrNumber = 0x28ac3c 
ptrNumber = 0x800102c0 
>>> *ptrNumber = 10 

==================change(int*& ptr)==================== 
    &ptr = 0x28ac3c 
    ptr = 0x800102c0 
======================================================= 

<<< *ptrNumber = 100 

De la sortie ci-dessus, nous voyons

&ptrNumber = &ptr 

Ainsi, ptr est alias de ptrNumber. Vous pouvez modifier ptrNumber dans la fonction void change (int * & ptr) en modifiant ptr. Par exemple, vous pouvez pointer ptr vers un autre emplacement de mémoire comme ci-dessous:

#include <iostream> 
using namespace std; 

void change(int*& ptr) { 
    cout << endl; 
    cout << "==================change(int*& ptr)====================" << endl; 
    cout << " &ptr = " << &ptr << endl; 
    cout << " >>> ptr = " << ptr << endl; 
    ptr = new int(20); 
    cout << " <<< ptr = " << ptr << endl; 
    cout << "=======================================================" << endl; 
    cout << endl; 
} 

int main(void) { 
    int* ptrNumber = new int(10); 

    cout << endl; 
    cout << ">>> &ptrNumber = " << &ptrNumber << endl; 
    cout << ">>> ptrNumber = " << ptrNumber << endl; 
    cout << ">>> *ptrNumber = " << *ptrNumber << endl; 
    change(ptrNumber); 
    cout << "<<< &ptrNumber = " << &ptrNumber << endl; 
    cout << "<<< ptrNumber = " << ptrNumber << endl; 
    cout << "<<< *ptrNumber = " << *ptrNumber << endl; 
} 

sortie Nouveau:

$ ./out_pointer.exe 

>>> &ptrNumber = 0x28ac3c 
>>> ptrNumber = 0x800102c0 
>>> *ptrNumber = 10 

==================change(int*& ptr)==================== 
    &ptr = 0x28ac3c 
    >>> ptr = 0x800102c0 
    <<< ptr = 0x80048328 
======================================================= 

<<< &ptrNumber = 0x28ac3c 
<<< ptrNumber = 0x80048328 
<<< *ptrNumber = 20 
Questions connexes