2009-05-05 9 views
96

Por lo que puedo ver, no hay ninguna razón por la que no se me permita pasar una referencia a un puntero en C++. Sin embargo, mis intentos de hacerlo están fallando, y no tengo idea de por qué.Pasando referencias a punteros en C++

Esto es lo que estoy haciendo:

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

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

Y estoy recibiendo este error:

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

Respuesta

91

Su función espera una referencia a un puntero de cadena real en el ámbito de llamada, no un puntero de cadena anónimo. Por lo tanto:

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

debería compilar muy bien.

Sin embargo, esto solo es útil si tiene la intención de modificar el puntero que pasa a la función. Si tiene la intención de modificar la cadena en sí, debe usar una referencia a la cadena como lo sugirió Sake. Con esto en mente, debería ser más obvio por qué el compilador se queja de su código original. En su código, el puntero se crea 'sobre la marcha', modificando que el puntero no tendría consecuencia y que no es lo que se pretende. La idea de una referencia (frente a un puntero) es que una referencia siempre apunta a un objeto real.

3

Probar:

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

Por lo que estoy haciendo, necesito la dirección del puntero y del puntero. No quiero pasar el puntero por valor. – Alex

+0

Aún no entiendo lo que trata de lograr. No puede tener "dirección del puntero" de "cadena s", simplemente porque "cadena s" no es un puntero. – Sake

+0

@Alex: supongo que necesita detectar si la cadena es exactamente igual a otra que está almacenando y no solo si sus contenidos son los mismos. Si ese es el caso, tenga en cuenta que puede usar el operador de dirección de referencia y obtendrá la dirección del objeto al que se hace referencia: void f (std :: string const & s) {std :: string const * p = & s; } –

7

Cambiar a:

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

EDIT:

Esto se llama ref-to-pointer y no se puede pasar a la dirección temporal como una referencia a la función. (a menos que sea const reference).

Aunque, he mostrado std::string* pS = &s; (puntero a una variable local), su uso típico sería: cuando desea que el destinatario cambie el puntero en sí, no el objeto al que apunta. Por ejemplo, una función que asigna memoria y asigna la dirección del bloque de memoria se asigna a su argumento debe tener una referencia a un puntero o un puntero a puntero:

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

} 
-1

Yo sé que es Posible para pasar referencias de punteros, lo hice la semana pasada, pero no recuerdo cuál fue la sintaxis, ya que su código parece correcto para mi cerebro en este momento. Sin embargo, otra opción es utilizar punteros de punteros:

Myfunc(String** s) 
5

&s produce puntero temporal para la cadena y no se puede hacer referencia al objeto temporal.

+4

Esto no es del todo cierto - puede hacer referencia a const temporal –

75

El problema es que está intentando vincular un temporal a la referencia, lo que C++ no permite a menos que la referencia sea const.

Así que se puede hacer ya sea uno de los siguientes:

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

Es especialmente instructivo escribir el tipo como lo hace el Sr. Burr en el ejemplo No.2 - 'cadena * const & val' en lugar de un equivalente menos legible como por ejemplo 'const string * & val'. Para mí, esto es claramente una const_reference_, un puntero, una cadena. Personalmente prefiero escribir 'T const &' en lugar de 'const T &' en declaraciones para obtener esta aclaración exacta. – fish2000

+1

Nit pick (no una crítica): Para mí, la frase 'bind a temporary to the reference' es más clara en esta respuesta que @Chris 'como' referencia a un puntero de cadena real en el ámbito de llamada, no a un puntero de cadena anónimo' . De todos modos, ambos son probablemente correctos desde mi punto de vista. – kevinarpe

+1

@ fish2000 No solo eso, 'const string * &' y 'string * const &' son en realidad tipos diferentes. La primera es una referencia que no es '' const '' a 'const string *', mientras que la segunda es una referencia 'const' a' 'string *'. –

2

EDIT: He experimentado algunos, y descubrí que son un poco más sutil de lo que pensaba.Esto es lo que ahora creo que es una respuesta precisa.

&s no es un lvalue, por lo que no puede crear una referencia a menos que el tipo de referencia sea const. Así, por ejemplo, no se puede hacer

string * &r = &s; 

pero se puede hacer

string * const &r = &s; 

Si se pone una declaración similar en la cabecera de la función, que va a funcionar.

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

Existe otro problema, a saber, los temporales. La regla es que puede obtener una referencia a un temporal solo si es const. Entonces, en este caso, se podría argumentar que & s es temporal, y por lo tanto debe declararse const en el prototipo de la función. Desde un punto de vista práctico, no hay diferencia en este caso. (Es un valor rvalue o temporal. De cualquier manera, se aplica la misma regla). Sin embargo, estrictamente hablando, creo que no es un valor temporal sino un valor. Me pregunto si hay una manera de distinguir entre los dos. (Tal vez simplemente se define que todos los temporales son valores r, y todos los valores no son temporales. No soy un experto en el estándar.)

Habiendo dicho esto, su problema es probablemente en un nivel superior. ¿Por qué quiere una referencia a la dirección de s? Si desea una referencia a un puntero a s, es necesario definir un puntero como en

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

si quieres una referencia a s o un puntero a s, hacer lo que es sencillo.

-8

myfunc ("cadena * & val") esto en sí mismo no tiene ningún sentido. "string * & val" implica "string val", * y & se cancelan entre sí. Finalmente, no se puede pasar la variable de cadena a una función ("string val"). Solo se pueden pasar tipos de datos básicos a una función, para que otros tipos de datos deban pasar como puntero o referencia. Puede tener la cadena & val o string * val en una función.

+3

Incorrecto en todos los niveles. Actualice la sintaxis de la declaración var. – Ari

1

Acabo de utilizar una referencia a un puntero para hacer todos los punteros en un árbol binario borrado excepto la raíz segura. Para que el puntero sea seguro, solo tenemos que establecerlo en 0. No pude hacer que la función que elimina el árbol (manteniendo solo la raíz) acepte una referencia a un puntero ya que estoy usando la raíz (este puntero) como la primera entrada para cruzar a izquierda y derecha.

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 pocas palabras, una referencia a un puntero no es válido cuando el parámetro formal es el (este) del puntero.

0

Bienvenido a C++ 11 y rvalue referencias:

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

Ahora usted tiene acceso al valor del puntero (contempladas en el val), que es la dirección de la cadena.

Puede modificar el puntero y a nadie le importará. Ese es un aspecto de lo que es un valor en primer lugar.

Tenga cuidado: El valor del puntero solo es válido hasta que myfunc() regresa. Por fin, es un temporal.

Cuestiones relacionadas