08 августа 2008

String parameters

Пытался установить Visual Studio 2005 Service Pack 1 на машине, у которой всего полтора гигабайта свободного места на диске. Думаете получилось? Нифига - места на диске не хватило!

Этот сервис пак представляет собой .exe размером 500Mb, внутри которого .msp, а внутри .msp видимо все обновляемые файлы лежат. То сначала распаковывается содержимое .exe в Temp, потом туда же распаковывается содержимое .msp, и видимо там дальше еще что-то распаковывается... Вобщем, красота.

К чему это я - к тому как часто передаются строки в качестве параметров. Строка в C++ - чаще всего std::basic_string:
void foo(const std::string& Param);
Если у нас строка хранится не в std::string, а например в const char*, то получим неявное копирование строки в конструкторе std::string.

void foo(const char* Param);
Уже лучше - можем передать string.c_str(), можем что угодно другое, где есть null terminator. А если у нас строка (или даже большой текст) загружен из ресурсов и есть const char* data() и size_t size(), но нет замыкающего нуля - снова придется делать копию. И это не единственный вариант, когда есть data()/size() - если хотим передать подстроку (внутреннюю часть какой-либо большой строки), то возникнет та же проблема.

void foo(const char* Param, size_t Size = strlen(Param));
Уже намного лучше. Правда если строка в другой кодировке или вообще, читается с потока - опять нужно складывать копию в память, а потом только вызывать foo().

А хорошая альтернатива - это парочка итераторов (a-la STL) или контейнер (a-la Boost):
template <typename T>> void foo(T First, T Last);
template <typename T>> void foo(const &T String);

Конструкции почти эквивалентны, т.к. у контейнера легко можно взять String.begin() и String.end(), а пару итераторов - скормить boost::make_iterator_range(). Так что скорее вопрос вкуса, какой вариант выбрать - я за контейнер.

С таким интерфейсом мы можем взять свести копирование к минимуму. Например, пришли данные в urlencode, да еще в win1251:
char* data = "q=%EF%F0%E8%E2%E5%F2&a=%EC%E5%E4%E2%E5%E4";

Парсим все в указатели:
typedef std::pair<char*, char*> substr;
typedef std::pair<substr, substr> item;


Делаем итератор для декодирования urldecode ("%EF%F0%E8%E2%E5%F2" -> "привет") - и его operator* и operator++ будут делать всю работу "на ходу". (Тут можно призвать на помощь boost::iterator_facade). Нужно конвертировать в utf-8? - еще один итератор ;) И все это скормим нашей foo().

PS. Подробности такого подхода - в boost.iterator, boost.range, boost.string algo.

1 комментарий:

Анонимный комментирует...

http://nsentinel.blogspot.com/2007/01/tweak-visual-studio-2005-sp1.html

о специфики установки этого СП.