Passando i riferimenti ai puntatori in C ++

Per quanto posso dire, non c‘è motivo per cui non dovrebbe essere permesso di passare un riferimento a un puntatore in C ++. Tuttavia, i miei tentativi di farlo stanno fallendo, e non ho idea del perché.

Questo è quello che sto facendo:

void myfunc(string*& val) { // Do stuff to the string pointer } // sometime later { // ... string s; myfunc(&s); // ... } 

E sto ricevendo questo errore:

imansible convertire il parametro 1 da ‘std :: string *’ a ‘std :: string * &’

La tua funzione si aspetta un riferimento a un puntatore di stringa effettivo nell’ambito di chiamata, non a un puntatore di stringa anonimo. Così:

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

dovrebbe compilare bene.

Tuttavia, questo è utile solo se si intende modificare il puntatore che si passa alla funzione. Se intendi modificare la stringa stessa dovresti usare un riferimento alla stringa come suggerito da Sake. Con questo in mente dovrebbe essere più ovvio perché il compilatore si lamenta del tuo codice originale. Nel tuo codice il puntatore viene creato “al volo”, la modifica di quel puntatore non avrebbe conseguenze e non è ciò che è inteso. L’idea di un riferimento (rispetto a un puntatore) è che un riferimento punta sempre su un object reale.

Il problema è che stai cercando di associare un riferimento temporaneo al riferimento, che C ++ non consente a meno che il riferimento non sia const .

Quindi puoi fare una delle seguenti cose:

 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; } 

Cambiarlo in:

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

MODIFICARE:

Questo è chiamato ref-to-pointer e non è ansible passare l’indirizzo temporaneo come riferimento alla funzione. (a meno che non sia un const reference ).

Tuttavia, ho mostrato std::string* pS = &s; (puntatore a una variabile locale), il suo uso tipico sarebbe: quando si desidera che il callee cambi il puntatore stesso, non l’object a cui punta. Ad esempio, una funzione che alloca la memoria e assegna l’indirizzo del blocco di memoria che ha assegnato al suo argomento deve prendere un riferimento a un puntatore o un puntatore al puntatore:

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

&s produce un puntatore temporaneo alla stringa e non è ansible fare riferimento a un object temporaneo.

Provare:

 void myfunc(string& val) { // Do stuff to the string pointer } // sometime later { // ... string s; myfunc(s); // ... } 

o

 void myfunc(string* val) { // Do stuff to the string pointer } // sometime later { // ... string s; myfunc(&s); // ... } 

EDIT: Ho sperimentato alcuni, e ho scoperto che le cose sono un po ‘più sottili di quanto pensassi. Ecco quello che ora penso sia una risposta accurata.

&s non è un lvalue quindi non è ansible creare un riferimento ad esso a meno che il tipo di riferimento non sia riferimento a const . Quindi, per esempio, non puoi farlo

 string * &r = &s; 

ma tu puoi farlo

 string * const &r = &s; 

Se inserisci una dichiarazione simile nell’intestazione della funzione, funzionerà.

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

C’è un altro problema, vale a dire i provvisori. La regola è che puoi ottenere un riferimento a un temporaneo solo se è const . Quindi in questo caso si potrebbe sostenere che & s è temporaneo, e quindi deve essere dichiarato const nel prototipo della funzione. Da un punto di vista pratico non fa differenza in questo caso. (È un valore o un valore temporaneo. Ad ogni modo, si applica la stessa regola.) Tuttavia, a rigor di termini, penso che non sia un valore temporaneo, ma un valore. Mi chiedo se c’è un modo per distinguere tra i due. (Forse è semplicemente definito che tutti i provvisori sono valori validi e tutti i non valori sono temporanei. Non sono un esperto dello standard.)

Detto questo, il tuo problema è probabilmente ad un livello più alto. Perché vuoi un riferimento all’indirizzo di s ? Se si desidera un riferimento a un puntatore a s , è necessario definire un puntatore come in

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

Se vuoi un riferimento a s o un puntatore a s , fai la cosa semplice.

Ho appena fatto uso di un riferimento a un puntatore per fare tutti i puntatori in un albero binario cancellato eccetto il root safe. Per rendere il puntatore sicuro, dobbiamo solo impostarlo su 0. Non posso creare la funzione che cancella l’albero (mantenendo solo la radice) per accettare un riferimento a un puntatore poiché sto usando la radice (questo puntatore) come prima input per attraversare sinistra e destra.

 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 

In conclusione, un riferimento a un puntatore non è valido quando il parametro formale è il puntatore (this).

Benvenuti in C ++ 11 e riferimenti rvalue:

 #include  #include  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); // ... } 

Ora avete accesso al valore del puntatore (riferito a val ), che è l’indirizzo della stringa.

È ansible modificare il puntatore e a nessuno importa. Questo è un aspetto di ciò che un valore è in primo luogo.

Fai attenzione: il valore del puntatore è valido fino a quando myfunc() ritorna. Alla fine, è un temporaneo.

So che è ansible passare dei riferimenti ai puntatori, l’ho fatto la settimana scorsa, ma non riesco a ricordare quale sia stata la syntax, dato che il tuo codice sembra corretto al mio cervello in questo momento. Tuttavia un’altra opzione è usare i puntatori dei puntatori:

 Myfunc(String** s) 

myfunc (“stringa * e val”) questo stesso non ha alcun senso. “string * & val” implica “stringa val”, * e & si annulla a vicenda. Infine non si può passare una variabile stringa ad una funzione (“stringa val”). Solo i tipi di dati di base possono essere passati a una funzione, poiché altri tipi di dati devono passare come puntatore o riferimento. Puoi avere string & val o string * val per una funzione.