¿Cuáles son las diferencias entre las definiciones de parámetros como (tipo y nombre) y (nombre tipo *)?

StackOverflow https://stackoverflow.com/questions/948947

  •  09-09-2019
  •  | 
  •  

Pregunta

Una pregunta muy básica, pero aún así, sería bueno saber de los gurús de C ++ que hay.

Hay dos formas bastante similares para declarar parámetros por referencia en C ++.

1) El uso de "asterisco":

void DoOne(std::wstring* iData);

2) El uso de "ampersand":

void DoTwo(std::wstring& iData);

¿Cuáles son las implicaciones de cada método? ¿Hay algunas pifias en cualquier caso?

Bono # 1: ¿Cuál sería una manera formal de llamar al método en el # 1 y # 2? ¿Son ambos llamados "por referencia"?

Bono # 2: std :: wstring se utiliza deliberadamente. ¿Cuáles serían las implicaciones hacia la librería de clases estándar en cada caso?

¿Fue útil?

Solución

# 1 utiliza un parámetro de puntero ( 'que pasa un puntero a'), # 2 utiliza un parámetro de referencia ( 'que pasa por referencia'). Son muy similares, pero tenga en cuenta que el código de llamada se ve diferente en los dos casos:

std::wstring s;

DoOne(&s); // pass a pointer to s
DoTwo(s); // pass s by reference

Algunas personas prefieren # 1, utilizando una convención que pasa por el puntero indica que la función puede cambiar el valor de s (a pesar de que ambas funciones podría). Otras personas (yo incluido) prefieren # 2, ya que el paso por referencia no permite NULL que se pasa.

Hay otra diferencia importante al pasar por el puntero const o referencia. Una variable temporal solamente se puede pasar a un parámetro de referencia const:

void ByConstPointer(const std::wstring&);
void ByConstReference(const std::wstring*);

void test()
{
  ByConstPointer(&std::wstring(L"Hello")); // error: cannot take address of temporary
  ByConstReference(std::wstring(L"Hello")); // fine
}

Otros consejos

La regla número uno para esto: Si NULL es un valor válido para el parámetro de la función en el contexto de la función, y luego pasarlo como puntero, de lo contrario pasarlo como referencia

.

Justificación, si no puede (no debe!) Jamás ser NULL, entonces no se ponga por el problema de la comprobación de NULL.

Al escribir ejemplos, se me ocurrió con mi propia respuesta. Cualquier cosa que no sea de abajo?

El resultado de cada uno de ellos es bastante similar: una referencia a un objeto en la memoria termina dentro del alcance del método. No parecen existir requisitos de memoria estrictas para cualquiera de ellos. El objeto puede ser o bien en la pila o en el montón.

En el caso de la pila cada uno de los métodos se llamaría así:

{
    std::wstring data;
    DoOne(&data);
    DoTwo(data);
}

Sin embargo, cuando se trata de la pila, el segundo enfoque requeriría que el objeto debe existir antes de llamar al método. Si no existe el objeto, la persona que llama causaría excepción, no la parte llamada.

{
    std::wstring* pData = new std::wstring();
    DoOne(pData);
    DoTwo(*pData);
}

En el ejemplo anterior, si fuera de la memoria y la condición se produce pData termina NULL, el accidente podría suceder antes de DoTwo, pero DOONE se tragaría el NULL y se puede bloquear algún tiempo más tarde.

Yo no diría yo una figura C ++ (a excepción de en mi CV), pero yo diría; a menos que theres cualquier uso de pasar el parámetro como un puntero (es decir, la función quiere comprobar para null), utilizar siempre una referencia.

Esto también se aplica a las funciones de regresar objetos, devolviendo un puntero de alguna manera está diciendo que el usuario de la clase que podría ser nulo.

En DOONE, iData se pueden asignar NULL. Si utiliza que después de llamar DOONE, la aplicación se bloquee.

Algo así como

void DoOne(std::wstring* iData)
{
   //Use iData
   delete iData;
   iData = NULL;
}

y

{
    std::wstring* pData = new std::wstring();
    DoOne(pData);
    pData->someFunction(); //Crash
}

Su respuesta es completamente equivocado cuando dice:

  

El resultado de cada uno de ellos es bastante   similar: una referencia a un objeto en   la memoria termina dentro del método   alcance. No parece haber ninguna estricta   requisitos de memoria para cualquiera de ellos.

connsider:

void f( int * p1 ) {
   int ** p2 = & p1;
}

aquí P1 tiene un claro "requisito de memoria" - que debe existir y que debe ser capaz de tomar su dirección. Contrasta esto con

void f( int & r ) }
   int * p = & r;
}

r aquí no tiene existencia propia, que no es más que una referencia. Whem tomo su dirijo estoy tomando la dirección de lo que se refiere a r.

Sus observaciones sobre el puntero NULL también se equivocan. Derefrencing el puntero NULL provoca un comportamiento indefinido - esto puede o no puede dar lugar a un accidente.

Si se escribe una función que recibe una variable puntero, lo más probablemente, tiene que comprobar si el puntero es válido (por ejemplo, no es NULL), de lo contrario corre el riesgo de caída del programa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top