2010-02-13 2 views
5

Delphi использует подсчет ссылок со строками.Строки Delphi и подсчет ссылок

Означает ли это, что имеется только одно распределение памяти для '1234567890' и все ссылки a, b, c, d, e и f.s?

type 
    TFoo = class 
    s: string; 
    end; 

    const 
    a = '1234567890'; 
    b = a; 
    c : string = a; 

    var 
    d: string; 
    e: string; 
    f: TFoo; 

    function GetStr1(const s: string): string; 
    begin 
    Result := s; 
    end; 

    function GetStr2(s: string): string; 
    begin 
    Result := s; 
    end; 

    begin 
    d := GetStr1(b); 
    e := GetStr2(c); 
    f := TFoo.Create; 
    f.s := a; 
    end; 
+2

(обратите внимание, что если вы включите «использование отладки dcus» вы можете отслеживать с помощью кода, хелперы включительно) –

ответ

9

Да, в вашем конкретном примере есть только одно выделение. Если вы использовали UniqueString, как говорит mghie, или если вы построили строку динамически, то вы получите новое распределение строк, даже если содержимое строки совпадает с некоторой другой строкой.

Однако интересный факт о вашем конкретном примере: на самом деле нет памяти «выделено» для строки «1234567890». Данные для строковых констант хранятся в исполняемом образце на диске и выгружаются ОС, когда код обращается к нему. Он занимает адресное пространство памяти, как часть отображения всего исполняемого модуля в памяти, но поскольку он поддерживается исходным исполняемым файлом на диске, он не является частью памяти, обработанной процессом, и не нуждается в поддержке в Файл подкачки.

Например, эта программа будет сообщать о нарушении прав доступа на бегу:

{$apptype console} 
uses SysUtils; 

const 
    s = '1234567890'; 
procedure Change(const r: string); 
var 
    p: PChar; 
begin 
    p := PChar(r); 
    p^ := 'x'; 
end; 

begin 
    try 
    Change(s); 
    except 
    on e: Exception do 
     Writeln(e.Message); 
    end; 
end. 
+0

Внимательно. Мы должны быть осторожны при использовании указателей. – pKarelian

+0

Если я объявляю const s: string = '1234567890'; нарушение прав доступа не поднимается? (I не может проверить его сейчас) – pKarelian

+1

const s: string = '... не имеет никакого значения в Delphi 7. Компилятор вызывает System._LStrLAsg (var dest; const source), который устанавливает dest, указывающий на const. НО, если строка dest является GLOBAL, тогда компилятор вместо этого вызывает System._LStrAsg. Исходный код отмечает, что это делается для совместимости с DLL. –

5

да, струны исх подсчитывали, копия создается только тогда, когда содержимое модифицируются через переменную (копия семантики записи), подробнее здесь:

http://www.codexterity.com/delphistrings.htm

+0

Хороший намек. Так что умный Delphi не теряет refence, когда функция возвращает строку. – pKarelian

+0

http://www.codexterity.com/delphistrings.htm «WideString ведет себя точно так же, как AnsiString, автоматически управляется, завершает нуль и * ссылается на подсчет *» -> WideString не засчитываются! – kibab

+0

https://web.archive.org/web/20100323193851/http://www.codexterity.com/delphistrings.htm не так? Из RADStudio «Тип WideString представляет собой динамически выделенную строку из 16-разрядных символов Unicode. В некоторых отношениях она похожа на AnsiString. В Win32 WideString совместим с типом COM BSTR. WideString подходит для использования в COM-приложениях. Однако, WideString не подсчитывается по ссылке, поэтому UnicodeString более гибкая и эффективная в других типах приложений ». – robocat

6

Небольшое дополнение к answer by jxac:

копия также будет создана, когда UniqueString() вызывается в коде, когда символ в строке имеет доступ [], и когда строка typecasted для PChar. Это происходит даже тогда, когда PChar и строковый элемент будут только когда-либо прочитаны.

Важно знать, как принудительно создать уникальную строку из потенциально общего, поскольку существуют функции Windows API, которые нельзя вызывать с помощью указателя на чтение, который имеет значение PChar для строковой константы. В этом случае константу нужно сначала скопировать в переменную, поэтому при ее нажатии возвращается PChar, указывающая на записываемую память.

+0

Да. Я заметил, что когда я вызвал функцию dll с параметром PChar, который возвращает данные :-( – pKarelian

Смежные вопросы