>>Т.е. к сожалению вопрос осталя без ответа - откуда AccessViolation?
Ну даже в коде, который привёл Aristarh Dark, после выделения памяти происходит очистка старого содержимого Dest - вызывается _LStrClr или _UStrClr.
Смотрите что там делается
Запоминается старое значение, которое было в строке
здесь используется приведение к Pointer, чтобы убрать "магию" компилятора.
Затем заказывается память под новую строку
Код:
Pointer(Dest) := _NewUnicodeString(CharLength);
Строка выделяется с уже установленым в 1 счётчиком. Опять "магия" не используется.
Код:
if Source <> nil then
Move(Source^, Pointer(Dest)^, CharLength * SizeOf(WideChar));
Если был успешный заказ пямяти, то копируем в строку переданный буфер.
Всё как Вы думали.
А затем
В самой первой строке процедуры мы запомнили в переменной Temp то, что раньше было в Dest. А далее
Код:
procedure _UStrClr(var S);
asm
JMP _LStrClr
end;
просто переход на функцию
Код:
procedure _LStrClr(var S);
{$IFDEF PUREPASCAL}
var
P: PStrRec;
begin
if Pointer(S) <> nil then
begin
P := Pointer(Integer(S) - Sizeof(StrRec));
Pointer(S) := nil;
if P.refCnt > 0 then
if InterlockedDecrement(P.refCnt) = 0 then
FreeMem(P);
end;
end;
{$ELSE}
asm
{ -> EAX pointer to str }
MOV EDX,[EAX] { fetch str }
TEST EDX,EDX { if nil, nothing to do }
JE @@done
MOV dword ptr [EAX],0 { clear str }
MOV ECX,[EDX-skew].StrRec.refCnt { fetch refCnt }
DEC ECX { if < 0: literal str }
JL @@done
LOCK DEC [EDX-skew].StrRec.refCnt { threadsafe dec refCount }
JNE @@done
PUSH EAX
LEA EAX,[EDX-skew].StrRec.codePage { if refCnt now zero, deallocate}
CALL _FreeMem
POP EAX
@@done:
end;
{$ENDIF}
которая и выполняет пункты 1)-5) из моего первого поста. На шаге 4) и происходит облом.