2009-05-05 16 views
96

Per quanto posso dire, non c'è motivo per cui non debba essere consentito passare un riferimento a un puntatore in C++. Tuttavia, i miei tentativi di farlo stanno fallendo, e non ho idea del perché.Passaggio di riferimenti a puntatori in C++

Questo è quello che sto facendo:

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

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

e sto ottenendo questo errore:

cannot convert parameter 1 from 'std::string *' to 'std::string *&'

risposta

91

La funzione prevede un riferimento a un puntatore di stringa effettivo nell'ambito di chiamata, non un puntatore di stringa anonimo. Quindi:

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

deve essere compilato correttamente.

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 oggetto reale.

3

Prova:

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); 
    // ... 
} 
+0

Per quello che sto facendo, però, ho bisogno dell'indirizzo del puntatore e del puntatore stesso. Non voglio passare il puntatore in base al valore. – Alex

+0

Ancora non capisco cosa cerchi di realizzare. Non puoi avere "indirizzo del puntatore" di "stringa s", semplicemente perché "stringa s" non è un puntatore. – Sake

+0

@Alex: Considero che è necessario rilevare se la stringa è esattamente la stessa di un'altra che si sta memorizzando e non solo se il loro contenuto è lo stesso. Se questo è il caso, si noti che è possibile utilizzare l'operatore address-of per un riferimento e otterrà l'indirizzo dell'oggetto referenziato: void f (std :: string const & s) {std :: string const * p = & s; } –

7

modificarla in:

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

EDIT:

Questo si chiama ref-to-pointer e non si può passare indirizzo temporaneo come riferimento per funzionare. (a meno che non sia const reference).

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

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

} 
-1

So che è posible passare riferimenti di puntatori, l'ho fatto la scorsa settimana, ma non riesco a ricordare quale fosse la sintassi, dato che il tuo codice sembra corretto al mio cervello proprio ora. Tuttavia un'altra opzione è quella di utilizzare i puntatori di puntatori:

Myfunc(String** s) 
5

&s produce puntatore temporaneo stringa e non si può fare riferimento a oggetto temporaneo.

+4

Questo non è del tutto vero - puoi creare un riferimento a const temporaneo –

75

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

Così si può fare una delle due seguenti operazioni:

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

È particolarmente istruttivo scrivere il tipo nel modo in cui Mr. Burr fa nell'esempio n. 2 - 'string * const & val' invece di un equivalente meno leggibile come ad es 'const string * & val'. Ai miei occhi questo è chiaramente un const_reference_, un puntatore, una stringa. Personalmente preferisco scrivere 'T const &' invece di 'const T &' nelle dichiarazioni per ottenere questo chiarimento esatto. – fish2000

+1

Nit pick (non una critica): per me, la frase 'associare un riferimento temporaneo al riferimento' è più chiara in questa risposta di @Chris 'come riferimento a un puntatore di stringa effettivo nell'ambito di chiamata, non a un puntatore di stringa anonimo' . Indipendentemente da ciò, entrambi sono probabilmente corretti dal mio punto di vista. – kevinarpe

+1

@ fish2000 Non solo, 'const string * &' e 'string * const &' sono in realtà tipi diversi. Il primo è un riferimento non-'coer * a una' const string * ', mentre il secondo è un riferimento' const' a una 'stringa *'. –

2

EDIT: Ho sperimentato un po ', e ho scoperto cosa sono un po' più sottile di quanto pensassi.Ecco quello che ora penso sia una risposta accurata.

&s non è un lvalue quindi non è possibile creare un riferimento ad esso a meno che il tipo di riferimento sia riferimento a const. Così, per esempio, non si può fare

string * &r = &s; 

ma si può fare

string * const &r = &s; 

Se si mette una dichiarazione simile nell'intestazione della funzione, funzionerà.

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

C'è un altro problema, vale a dire, 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 di 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 e tutti i non valori sono temporanei. Io non sono un esperto dello standard.)

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

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

Se si desidera un riferimento a s o un puntatore a s, fare la cosa semplice.

-8

myfunc ("stringa * & val") questo non ha alcun senso. "stringa * & val" implica "stringa val", * e & si annulla l'un l'altro. 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. È possibile avere una stringa & val o stringa * val per una funzione.

+3

Errato a tutti i livelli. Si prega di aggiornare la sintassi della dichiarazione var. – Ari

1

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 

Linea di fondo, un riferimento a un puntatore non valido quando il parametro formale è il (questo) puntatore.

0

Benvenuto C++ 11 e rvalue riferimenti:

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

Ora si ha accesso al valore del puntatore (a cui si riferisce val), che è l'indirizzo della stringa.

È possibile modificare il puntatore e nessuno si preoccuperà. Questo è un aspetto di ciò che un valore è in primo luogo.

Attenzione: il valore del puntatore è valido solo fino ai ritorni myfunc(). Alla fine, è un temporaneo.