Создание строк в D без выделения памяти? - PullRequest
8 голосов
/ 01 октября 2011

Есть ли какой-либо безопасный способ создания string в D, используя информацию, доступную только во время выполнения, без выделения памяти?

Простой пример того, что я мог бы сделать:

void renderText(string text) { ... }

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    renderText(text[0..n]); // ERROR
}

Используя это, вы получите ошибку, потому что срез text не является неизменным, и, следовательно, не является string (то есть immutable(char)[])

Я могу думать только о трехспособы обойти это:

  1. Приведите срез к string.Это работает, но безобразно.
  2. Выделите новую строку, используя фрагмент.Это работает, но я бы предпочел не выделять память.
  3. Измените renderText на const(char)[].Это работает здесь, но (а) это ужасно, и (б) многие функции в Фобосе требуют string, поэтому, если я хочу использовать их таким же образом, то это не сработает.

Ничто из этого не особенно приятно.Я что-то пропустил?Как все остальные обходят эту проблему?

Ответы [ 4 ]

6 голосов
/ 02 октября 2011

У вас есть статический массив char.Вы хотите передать его функции, которая принимает immutable(char)[]. only способ сделать это без какого-либо выделения - разыграть.Думаю об этом.То, что вы хотите, это один тип, чтобы действовать так, как будто это другой.Это то, что делает кастинг.Вы можете использовать assumeUnique, чтобы сделать это, поскольку это именно то, что вы ищете, но то, действительно ли это что-то приносит вам, является спорным.Его основная цель состоит в том, чтобы задокументировать, что то, что вы делаете с помощью приведения, заключается в том, чтобы преобразованное значение обрабатывалось как immutable, и что на него нет других ссылок.Глядя на ваш пример, это, по сути, так, поскольку это последнее, что есть в функции, но хотите ли вы сделать это в целом, решать только вам.Учитывая, что это статический массив, который рискует проблемами с памятью, если вы облажаетесь и передаете его функции, которая позволяет утечке ссылки на него, я не уверен, что assumeUnique - лучший выбор.Но опять же, это зависит от вас.

Независимо от того, если вы делаете приведение (будь то явно или с помощью assumeUnique), вы должны быть уверены, что функция, которой вы передаете это,не собирается пропускать ссылки на данные, которые вы передаете ему.Если это так, то вы напрашиваетесь на неприятности.

Другое решение, конечно, состоит в том, чтобы изменить функцию так, чтобы она заняла const(char)[], но при этом все еще существует риск утечки ссылок на данные.что вы передаете. Итак, вы все еще должны быть уверены в том, что на самом деле собирается делать функция.Если это pure, не возвращает const(char)[] (или что-либо, что может содержать const(char)[]), и нет никакого способа, которым он мог бы просочиться через любой из других аргументов функции, тогда вы в безопасности, но если таковые имеютсяиз этого не правда, тогда вы должны быть осторожны.Итак, в конечном счете, я считаю, что все, что использует const(char)[] вместо приведения к string, действительно покупает вас, так это то, что вам не нужно разыгрывать.Это все еще лучше, так как это позволяет избежать риска испортить актерский состав (и в целом лучше избегать каста, когда вы можете), но у вас все равно есть о чем беспокоиться в отношении экранирования ссылок.

Конечно, это также требует, чтобы вы могли изменить функцию, чтобы иметь нужную подпись.Если вы не можете этого сделать, вам придется сыграть.Я полагаю, что на данный момент большинство функций, основанных на строках Фобоса, были изменены так, что они основаны на строковом типе.Так что теперь это должно быть меньше проблем с Фобосом, чем раньше.Некоторые функции (в частности, те, что в std.file), все еще должны быть шаблонизированы, но в конечном итоге функции на Фобосе, для которых требуется string, должны быть довольно редкими и будут иметь веские основания для этого.* Однако, в конечном счете, проблема заключается в том, что вы пытаетесь обрабатывать статический массив как динамический массив, и хотя D определенно позволяет вам это делать, вы берете на себя определенный риск, и вам необходимоуверен, что используемые вами функции не пропускают никаких ссылок на локальные данные, которые вы им передаете.

2 голосов
/ 01 октября 2011

Выезд assumeUnique от std.exception Ответ Джонатана.

0 голосов
/ 01 октября 2011

Один из способов обойти это - скопировать изменяемые символы в новую неизменяемую версию, а затем нарезать:

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    immutable(char)[16] itext = text;
    renderText(itext[0..n]);
}

Однако:

  1. В настоящее время DMDразрешите это из-за ошибки.
  2. Вы создаете ненужную копию (лучше, чем выделение GC, но все же не очень).
0 голосов
/ 01 октября 2011

Нет, вы не можете создать строку без выделения .Вы имели в виду доступ ?Чтобы избежать выделения, вы должны использовать слайс или указатель для доступа к ранее созданной строке.Не уверен насчет приведения, он может выделять или не выделять новое пространство памяти для новой строки.

...