2012-03-03 110 views
7

Contexto 1Delphi paso de parámetros por referencia o por valor/copia

var text:String; 

text:='hello'; 

myFunc(text); 

Contexto2

function myFunc(mytext:String); 
var textcopy:String; 
begin 

    textcopy:=mytext; 

end; 

myFunc en la Contexto2 se llamó desde el Contexto1, la variable local mytext apunta a una memoria fuera el Context2? o el mytext tiene su propio espacio de memoria dentro del alcance y se ha rellenado/copiado con el mismo contenido del text? Probablemente me esté perdiendo algo realmente básico, porque me da un error access violation.

¿Hay alguna forma de especificar explícitamente si una función debe recibir parámetros por referencia o por valor, copiando luego como en C? No estoy seguro de cómo lo estoy haciendo.

+0

Normalmente, esto no debería dar como resultado un AV. Sospecho que estos códigos se ejecutan desde DLL separadas? Use 'ShareMem' entonces. – NGLN

+0

y 'algún error de violación de acceso' es? – RBA

+0

@NGLN sí, estoy usando un dll escrito en C++, así que escribí un archivo de encabezado pas. Y estoy obteniendo AV en situaciones en las que no puedo entender por qué, probablemente este paso por referencia y no copiar causa AV cuando trabajo con punteros. –

Respuesta

20

La gestión de la memoria para las cuerdas Delphi es un poco inusual. Después de llamar al myFunc(text) y asignar textcopy := mytext, las tres variables (text, mytext y textcopy) apuntarán a la misma dirección, la de la cadena original.

Pero tan pronto como utilice una de estas variables para realizar cambios en la cadena, Delphi clona la cadena detrás de las escenas y los cambios se aplican a la copia. Las otras dos variables aún apuntan al original, por lo que permanecen sin cambios. Por lo tanto, cualquier cambio realizado en el contexto 2 no se verá en el contexto 1: esta mecánica de "copiar con la escritura" proporciona efectivamente una semántica de valor por paso. Todas estas cadenas son contadas por referencia, y se liberarán automáticamente una vez que todas las referencias salgan del alcance.

Sin embargo, hay una excepción. Si accede a la cadena utilizando punteros, en lugar de operaciones de cadena, omitirá el paso de copia y los cambios afectarán al original. También omitirá la lógica de recuento de referencias y, potencialmente, terminará con un puntero a un bloque de memoria desasignado. Esta puede ser la razón detrás de su violación de acceso, pero no podría decir sin más detalles/más código.

Si desea pasar la referencia, declare su función como myFunc(var mytext: String). Si desea forzar a Delphi a copiar la cadena, en lugar de esperar hasta que se modifique, puede usar System.UniqueString.

+1

Eso es cierto, pero no es realmente útil para un principiante completo. El objetivo de toda la copia sobre magia de escritura es que hace que un tipo de referencia se comporte como un tipo de valor. Me temo que esta respuesta, por correcta que sea, simplemente confundirá aún más a un principiante ya muy confundido. –

+1

@David: No sé, me sonó como si tuviera una comprensión lo suficientemente decente de la semántica de llamadas y la asignación de memoria en general, simplemente no cómo funcionan específicamente en Delphi. Y aunque ciertamente estoy de acuerdo en que generalmente es mejor pasar por alto los detalles y dejar que Delphi haga su magia, calculé que una violación de acceso va a exigir una explicación de bajo nivel. –

+0

Editar respuesta mucho mejor. AV no está relacionado. Ver otra pregunta. –

6

En Delphi para el paso por referencia se agrega explícitamente la palabra clave var:

procedure myFunc(var mytext:String); 

Esto significa que myFunc puede modificar el contenido de la cadena y tener la persona que llama ver los cambios.

+0

En mi ejemplo 'text' y' mytext' cada uno tiene memoria separada asignada, ¿verdad? –

+0

@Vitimtk - No, 'text' y' mytext' hacen referencia a la misma memoria – kludg

9

En Delphi, la cadena es un tipo de referencia que normalmente actúa como un tipo de valor. Se asigna en el montón (no en la pila como la mayoría de los tipos de valor) y cuenta con recuento automático de referencias y semántica de copia con escritura.

Para comprender lo que esto significa, considere cómo los tipos de valores normales, p. Ej. un entero, se comportan cuando se pasa como un parámetro a un procedimiento: parámetro

var 
    gValue: Integer; 

procedure PassByValue(aValue: Integer); 
begin 
    // Here @gValue <> @aValue 
    aValue := aValue + 2; 
    // Here @gValue <> @aValue 
end; 

procedure PassByRefrenceInOut(var aValue: Integer); 
begin 
    // Here @gValue = @aValue 
    aValue := aValue + 2; 
    // Here @gValue = @aValue 
end; 

procedure CallProcedures; 
begin 
    gValue := 0; 
    PassByValue(gValue); 
    // gValue is still 0 
    PassByReferenceInOut(gValue); 
    // gValue is 2 
end; 

El var en PassByReferenceInOut es equivalente a la convención C de pasar un puntero a la discusión.

la misma semántica se aplican a la cadena de paso de parámetros, pero hay una sutil diferencia en la representación interna de los valores:

var 
    gValue: string; 

procedure PassByValue(aValue: string); 
begin 
    // Here PChar(gValue) = PChar(aValue) <<<< 
    aValue := aValue + '2'; 
    // Here PChar(gValue) <> PChar(aValue) 
end; 

procedure PassByRefrenceInOut(var aValue: string); 
begin 
    // Here PChar(gValue) = PChar(aValue) 
    aValue := aValue + '2'; 
    // Here PChar(gValue) = PChar(aValue) 
end; 

procedure CallProcedures; 
begin 
    gValue := ''; 
    PassByValue(gValue); 
    // gValue is still '' 
    PassByReferenceInOut(gValue); 
    // gValue is '2' 
end; 

Si desea asegurarse de que el procedimiento funciona con su propia copia de la cadena valor, utilice el procedimiento UniqueString, p. ej .:

procedure PassByValue(aValue: string); 
begin 
    // Here PChar(gValue) = PChar(aValue) 
    UniqueString(aValue); 
    // Here PChar(gValue) <> PChar(aValue) 
    aValue := aValue + '2'; 
    // Here PChar(gValue) <> PChar(aValue) 
end; 
+2

Primero es bueno explicar el comportamiento en un tipo de datos simple. – martinstoeckli

Cuestiones relacionadas