web-dev-qa-db-fra.com

Passer des références à des pointeurs en C ++

Autant que je sache, il n'y a aucune raison pour que je ne sois pas autorisé à transmettre une référence à un pointeur en C++. Cependant, mes tentatives pour y parvenir échouent et je ne sais pas pourquoi.

Voici ce que je fais:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

Et j'obtiens cette erreur:

ne peut pas convertir le paramètre 1 de 'std :: string *' en 'std :: string * &'

120
Alex

Votre fonction attend une référence à un pointeur de chaîne réel dans la portée de l'appel, pas à un pointeur de chaîne anonyme. Ainsi:

string s;
string* _s = &s;
myfunc(_s);

devrait compiler très bien.

Cependant, cela n'est utile que si vous avez l'intention de modifier le pointeur que vous passez à la fonction. Si vous avez l'intention de modifier la chaîne elle-même, vous devez utiliser une référence à la chaîne comme suggéré par Sake. Dans cet esprit, la raison pour laquelle le compilateur se plaint de votre code original devrait être plus évidente. Dans votre code, le pointeur est créé 'à la volée', la modification de ce pointeur n'aurait aucune conséquence et ce n'est pas ce qui est prévu. L'idée d'une référence (par rapport à un pointeur) est qu'une référence pointe toujours sur un objet réel.

118
Chris

Le problème est que vous essayez de lier un temporaire à la référence, ce que C++ n'autorise pas sauf si la référence est const.

Vous pouvez donc effectuer l’une des opérations suivantes:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}
84
Michael Burr

Changez le en:

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

MODIFIER:

C'est appelé ref-to-pointer et vous ne pouvez pas transmettre une adresse temporaire comme référence à une fonction. (sauf si c'est const reference).

Bien que j'ai montré std::string* pS = &s; (pointeur sur une variable locale), son utilisation typique serait: lorsque vous voulez que l'appelé modifie le pointeur lui-même, et non l'objet sur lequel il pointe. Par exemple, une fonction qui alloue de la mémoire et attribue l'adresse du bloc de mémoire alloué à son argument doit prendre une référence à un pointeur ou un pointeur à un pointeur:

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}
10
aJ.

&s produit un pointeur temporaire sur une chaîne et vous ne pouvez pas faire référence à un objet temporaire.

5
n0rd

Essayer:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

ou

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}
3
Sake

EDIT: J'ai expérimenté certains, et découvert que les choses sont un peu plus subtiles que je pensais. Voici ce que je pense maintenant être une réponse précise.

&s n'est pas une lvalue, vous ne pouvez donc pas y faire référence à moins que le type de référence ne soit référencé à const. Donc, par exemple, vous ne pouvez pas faire

string * &r = &s;

mais tu peux faire

string * const &r = &s;

Si vous mettez une déclaration similaire dans l'en-tête de la fonction, cela fonctionnera.

void myfunc(string * const &a) { ... }

Il existe un autre problème, à savoir les temporaires. La règle est que vous pouvez obtenir une référence à un temporaire uniquement s'il s'agit de const. Donc, dans ce cas, on pourrait dire que & s est temporaire et doit donc être déclaré const dans le prototype de la fonction. D'un point de vue pratique, cela ne fait aucune différence dans ce cas. (C'est une valeur ou une valeur temporaire. Dans les deux cas, la même règle s'applique.) Cependant, à proprement parler, je pense que ce n'est pas une valeur temporaire, mais une valeur. Je me demande s'il y a un moyen de distinguer les deux. (Peut-être est-il simplement défini que tous les temporaires sont des valeurs, et que tous les non-valeurs sont temporaires. Je ne suis pas un expert en standard.)

Cela étant dit, votre problème est probablement à un niveau supérieur. Pourquoi voulez-vous une référence à l'adresse de s? Si vous voulez une référence à un pointeur sur s, vous devez définir un pointeur comme dans

string *p = &s;
myfunc(p);

Si vous voulez une référence à s ou un pointeur sur s, faites les choses simplement.

2
Ari

Je viens d'utiliser une référence à un pointeur pour créer tous les pointeurs d'un arbre binaire supprimé, à l'exception du coffre-fort root. Pour sécuriser le pointeur, il suffit de le définir sur 0. Je ne pouvais pas créer la fonction qui supprime l’arborescence (en ne conservant que la racine) pour accepter une référence à un pointeur, car j’utilise la racine (ce pointeur) comme premier élément. entrée à traverser à gauche et à droite.

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

En bout de ligne, une référence à un pointeur n'est pas valide lorsque le paramètre formel est le pointeur (this).

1
Mohd

Bienvenue dans C++ 11 et les références rvalue:

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

Vous avez maintenant accès à la valeur du pointeur (désigné par val), qui correspond à l'adresse de la chaîne.

Vous pouvez modifier le pointeur et personne ne s'en souciera. C'est un aspect de ce qu'est une valeur en premier lieu.

Attention: la valeur du pointeur n'est valide que jusqu'au retour de myfunc(). Enfin, c'est temporaire.

0
not-a-user