Добавление UnicodeString к WideString в Delphi

Мне любопытно, что происходит с этим фрагментом кода в Delphi 2010:

function foo: WideString;
var 
   myUnicodeString: UnicodeString; 
begin
  for i:=1 to 1000 do
  begin
    myUnicodeString := ... something ...;

    result := result + myUnicodeString;  // This is where I'm interested
  end;
end;

Сколько преобразований строк задействовано и являются ли они особенно плохими с точки зрения производительности?

Я знаю, что вместо этого функция должна просто возвращать UnicodeString, но я видел этот анти-шаблон в коде потоковой передачи VCL и хочу понять процесс.


person Roddy    schedule 15.08.2013    source источник
comment
Вы пытались найти это в окне процессора отладчика?   -  person OnTheFly    schedule 15.08.2013
comment
@OnTheFly: на самом деле это часть проекта C++ Builder, и по какой-то причине BCB2010 не любит устанавливать точки останова в коде VCL ... Я попробую еще немного.   -  person Roddy    schedule 15.08.2013
comment
Если у вас нет Delphi для изучения сгенерированного кода для вашего tescase, я могу выложить дизассемблирование, но я действительно не уверен, как представить его в полезном виде...   -  person OnTheFly    schedule 15.08.2013
comment
@Roddy: установите флажок компоновщика, чтобы использовать отладочные DCU. (Проект->Параметры->Компилятор Delphi->Использовать отладочные DCU). Это позволит вам перейти к Delphi VCL и RTL из Builder.   -  person Ken White    schedule 15.08.2013


Ответы (2)


Чтобы ответить на ваш вопрос о том, что на самом деле делает код, это утверждение:

result := result + myUnicodeString;

Делает следующее:

  1. вызывает System._UStrFromWStr() для преобразования Result во временную UnicodeString

  2. вызывает System._UStrCat() для объединения myUnicodeString с временным

  3. вызывает System._WStrFromUStr(), чтобы преобразовать временный файл в WideString и назначить его обратно Result.

Существует функция System._WStrCat() для объединения WideString с WideStringSystem._UStrCat() для UnicodeString). Если бы CodeGear/Embarcadero подошли к этому с умом, они могли бы реализовать перегрузку System._WStrCat(), которая принимает UnicodeString в качестве входных данных и WideString в качестве выходных (и наоборот для объединения WideString с UnicodeString). Таким образом, больше не потребуется преобразований temp UnicodeString. И WideString, и UnicodeString закодированы как UTF-16 (ну, в основном, но я не буду вдаваться в это здесь), поэтому объединение их вместе — это просто вопрос одного выделения и перемещения, точно так же, как при объединении двух UnicodeString или двух WideString вместе. .

person Remy Lebeau    schedule 15.08.2013
comment
Спасибо, Реми. Это многое объясняет! - person Roddy; 15.08.2013

Производительность плохая. Нет необходимости в каких-либо преобразованиях кодировки, поскольку все кодируется UTF-16. Однако WideString представляет собой оболочку для типа COM BSTR, которая работает хуже, чем собственный UnicodeString.

Естественно, вы должны предпочесть выполнять всю свою работу с собственными типами, UnicodeString или TStringBuilder, и конвертировать в WideString в последний момент.

Это вообще хорошая политика. Вы не хотите использовать WideString внутри, так как это чисто тип взаимодействия. Так что конвертируйте в (и из) WideString только на границе взаимодействия.

person David Heffernan    schedule 15.08.2013
comment
Спасибо. Мне особенно любопытно, происходит ли concat строки (wide:=wide + uni) в домене unicode или в широком домене. Если это юникод, то задействованы два преобразования. (широкий-›uni, concat, uni-›широкий) - person Roddy; 15.08.2013
comment
Я не знаю эту конкретную деталь навскидку. Но это тривиально легко решить с помощью отладчика. Чего-то у меня сейчас нет. В любом случае, вы этого не хотите. Выполняйте всю свою работу с TStringBuilder и конвертируйте в WideString как можно позже. Все эти конкатенации были бы плохими даже с чистыми нативными строками. Тяжело в куче. - person David Heffernan; 15.08.2013
comment
На самом деле это не мой код. Он находится в class.pas в D2010 (CombineWideString). У меня была проблема, когда форма с одним строковым свойством размером 4 МБ (да, но на это есть веская причина!) загружалась 2,5 минуты (!) при использовании текстовых DFM и менее секунды при использовании двоичных файлов. - person Roddy; 15.08.2013
comment
Тогда ты ничего не сможешь с этим поделать. Вы знаете, что спектакль — ерунда. Просто не помещайте строку в файл dfm. - person David Heffernan; 15.08.2013
comment
На самом деле, вы можете что-то с этим сделать. Измените Classes.pas (ошибочный код находится в разделе implementation) и добавьте измененный файл в свой проект, чтобы он переопределял код RTL по умолчанию. Однако это работает только в том случае, если проект не использует пакеты времени выполнения. - person Remy Lebeau; 15.08.2013
comment
@Remy Ты ничего не можешь сделать легко. Комментарий о текстовом dfms дает понять, что это проблема времени разработки. - person David Heffernan; 15.08.2013
comment
@DavidHeffernan: на самом деле это вовсе не проблема времени разработки. Он использует DFM для потоковой передачи пользовательских файлов данных во время выполнения. см. это обсуждение. Так что мой предыдущий комментарий остается в силе. Отредактируйте Classes.pas, чтобы исправить проблему с производительностью (она была изначально исправлена ​​Embarcadero в XE3), и добавьте отредактированный файл в проект. - person Remy Lebeau; 15.08.2013
comment
@Реми Достаточно честно. Мне не хватало этой фоновой информации. Очевидно, что со стандартными файлами .dfm, связанными с формами и модулями данных, текстовый .dfm — это только время разработки. - person David Heffernan; 15.08.2013
comment
@DavidHeffernan, спасибо за ваш вклад - я должен был сделать ссылку на свое сообщение на форуме. IIRC, если вы используете текстовые DFM, они связаны с окончательным исполняемым файлом как текстовые ресурсы RCDATA, так что это потенциально проблема именно с этим. - person Roddy; 15.08.2013
comment
@ Родди, я так не думаю. Настройка Text DFM предназначена только для источника. Связанный исполняемый файл всегда имеет бинарные DFM. - person David Heffernan; 15.08.2013
comment
Ты прав, как обычно. Редактор ресурсов XN автоматически отображает их, как если бы они были текстом, что меня и зацепило... - person Roddy; 15.08.2013