Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Использование UniqueString


Автор: cemick 26.12.2009, 11:36
Наткнулся на тему http://stackoverflow.com/questions/1951192/delphi-performance-of-passing-const-strings-versus-passing-var-strings

и вот такой пример
 
Код

procedure TForm5.btn1Click(Sender: TObject);
var s:sTRING;
begin
   s := 'var string';
   UniqueString(s);
   SetCaption(s);
   Caption := s;
end;

procedure TForm5.SetCaption(const Value: string);
var
  p: PChar;
begin
  p := PChar(Value);
  p[3] := '?';
  Caption := Value;
end;


Мне не совсем понятно, что происходит и почему комментирование строчки  UniqueString(s); приводит к ошибке:

 
Код

procedure TForm5.btn1Click(Sender: TObject);
var s:sTRING;
begin
   s := 'var string';
  // UniqueString(s);  <--- Комментируем
   SetCaption(s);
   Caption := s;
end;

procedure TForm5.SetCaption(const Value: string);
var
  p: PChar;
begin
  p := PChar(Value);
  p[3] := '?'; < -- Получаем ошибку AV
  Caption := Value;
end;


Как я понимаю UniqueString гарантирует уникальность строки, просто копируя AnsiString строку в памяти.  Const же параметр передается по ссылки, но компилятор следит за тем, что бы значение параметра не менялось и не передався ни кому указатель на строку, где она могла бы изменится. Не понятно, почему после UniqueString, константная строка ведет себя как объект. Вот как то так не понятно.

Автор: Amphiluke 26.12.2009, 12:27
Цитата(Delphi help)

When you cast a long-string expression to a pointer, the pointer should usually be considered read-only. You can safely use the pointer to modify the long string only when all of the following conditions are satisfied.

  •  The expression cast is a long-string variable.
  •  The string is not empty.
  •  The string is unique--that is, has a reference count of one. To guarantee that the string is unique, call the SetLength, SetString, or UniqueString procedure.
  •  The string has not been modified since the typecast was made.
  •  The characters modified are all within the string. Be careful not to use an out-of-range index on the pointer.



Так что, видимо, это не только UniqueString() касается.
Код

  SetString(s, PChar('foo bar baz'), Length('foo bar baz'));
  SetConstCaption(s);
  Caption := s;


Автор: cemick 26.12.2009, 14:36
UniqueString не просто копирует строку в памяти? А вносит какие то изменения, которые позволяют при 
 p := PChar(Value);
 p[3] := '?';

определить что это уникальная строка? Ведь после s := 'var string'; количество ссылок на s тоже равно 1. Чем тогда отличается s от того, что получаем после UniqueString (s)

Автор: Amphiluke 26.12.2009, 15:27
Запись
Код

s := 'var string';

указывает компилятору разместить строковую константу в области сегмента кода, доступной только для чтения. Приведение типа к PChar не обеспечивает копирования строки из сегмента кода в динамическую память, а просто заносит указатель на константу в переменную типа PChar, поэтому попытка изменения строки приводит к AV.
А UniqueString как раз выполняет такое копирование в область памяти, доступную для изменения…

Да, впрочем, что рассказывать: вот http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1206 почитайте.

Автор: cemick 26.12.2009, 15:41
Цитата(Amphiluke @  26.12.2009,  15:27 Найти цитируемый пост)
указывает компилятору разместить строковую константу в области сегмента кода, доступной только для чтения. Приведение типа к PChar не обеспечивает копирования строки из сегмента кода в динамическую память, а просто заносит указатель на константу в переменную типа PChar, поэтому попытка изменения строки приводит к AV.
А UniqueString как раз выполняет такое копирование в область памяти, доступную для изменения…

Да, впрочем, что рассказывать: вот здесь почитайте.

хм, как я понял из  
Цитата

В третьем случае константа, как и раньше, размещается в сегменте кода. Счётчик ссылок у таких констант всегда равен -1 — это значение указывает менеджеру памяти, что это константа, которая не может быть изменена и память для которой не нужно освобождать.

var s: String;
s := 'var string'; - это константа размещенная в сегменте кода и у нее число ссылок должно быть равным -1?

Смотрю количество ссылок:
PInteger(Integer(@s[1])-8)^

Получаю 1. Почему?

Автор: Amphiluke 26.12.2009, 16:15
А вы посмотрели 5-й пример? Указатель, полученный с применением оператора @ указывает на область памяти, доступной для изменения. Следовательно, счетчик ссылок не равен -1.

Попробуйте:
Код

ShowMessage(IntToStr(Integer(PInteger(Integer(PChar(s))-8)^)));

Автор: cemick 26.12.2009, 16:40
Цитата(Amphiluke @  26.12.2009,  16:15 Найти цитируемый пост)
А вы посмотрели 5-й пример? Указатель, полученный с применением оператора @ указывает на область памяти, доступной для изменения. Следовательно, счетчик ссылок не равен -1.

Попробуйте:
код Pascal/Delphi
1:
ShowMessage(IntToStr(Integer(PInteger(Integer(PChar(s))-8)^)));



UniqString_Const.pas.32: P := @s[1];
0045A856 8D45F8           lea eax,[ebp-$08]
0045A859 E8E2A4FAFF       call @UniqueStringA
0045A85E 8945F0           mov [ebp-$10],eax

Во как оказывается, теперь все встало на свои места. Спасибо!

Первый раз сталкиваюсь с  областью "сегмент кода", поиск конечно же рулит, но может есть ссылки где можно поподробнее почитать об этом.


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)