Использование шаблонного класса строк strcmp, strcpy и strlen - PullRequest
3 голосов
/ 31 декабря 2011

Когда-то я слышал, как при создании класса шаблонной строки не следует использовать strcmp, strcpy и strlen для класса шаблонной строки, который может использовать UTF8 и UTF16. Из того, что я помню, вы предполагаете использовать функции изgorithm.h, однако я не помню, как реализация или почему это так. Может кто-нибудь объяснить, какие функции использовать вместо этого, как их использовать и почему?

Примером класса шаблонной строки будет что-то вроде

String<UTF8> utf8String;
String<UTF16> utf16String; 

Здесь UTF8 будет беззнаковым символом, а UTF16 - беззнаковым коротким.

Ответы [ 3 ]

6 голосов
/ 31 декабря 2011

Прежде всего, C ++ не нуждается в дополнительных строковых классах.Вероятно, уже разработано несколько сотен или тысяч слишком много строковых классов, и ваш не улучшит ситуацию.Если вы не делаете это исключительно для своего назидания, вы должны думать долго и усердно, а затем принять решение не писать новый.

Вы можете использовать std::basic_string<char> для хранения последовательностей кодовых единиц UTF-8, std::basic_string<char16_t> для хранения последовательностей кодовых единиц UTF-16, std::basic_string<char32_t> для хранения последовательностей кодовых единиц UTF-32 и т. д. C ++ даже предлагает короткие, удобные имена для этих типов: string, u16string и u32string.basic_string уже решает проблему, о которой вы здесь спрашиваете, предлагая функции-члены для копирования, сравнения и получения длины строки, которая работает для любой кодовой единицы, с которой вы ее шаблонируете.

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


С учетом вышесказанного причина, по которой вы не можете использовать strcmp, strcpy и strlen дляваш шаблонный строковый тип таков, что все они работают с нулевыми завершенными байтовыми последовательностями.Если ваша кодовая единица больше, чем один байт, тогда могут быть байты , которые равны нулю перед фактическим завершающим нулевым кодовой единицей (при условии, что вы вообще используете нулевое завершение, что, вероятно, не следует 'т).Рассмотрим байты этого UTF-16 представления строки «Hello» (на машине с прямым порядком байтов).

48 00 65 00 6c 00 6c 00  6f 00

Поскольку UTF-16 использует 16-битные единицы кода, символ «H» в конечном итоге сохраняетсякак два байта 48 00.Функция, работающая с вышеуказанной последовательностью байтов, предполагая, что первый нулевой байт является концом, предполагает, что вторая половина первого символа отмечает конец всей строки.Это явно не сработает.

Итак, strcmp, strcpy и strlen - все это специализированные версии алгоритмов, которые могут быть реализованы более широко.Поскольку они работают только с последовательностями байтов, и вам нужно работать с последовательностями единиц кода, где единица кода может быть больше байта, вам нужны универсальные алгоритмы, которые могут работать с любой единицей кода.Стандартная библиотека предлагает множество общих алгоритмов.Вот мои предложения по замене этих str* функций.

strcmp сравнивает две последовательности единиц кода и возвращает 0, если две последовательности равны, положительное, если первое лексикографически меньше, чем второе, и отрицательноеиначе.Стандартная библиотека содержит универсальный алгоритм lexicographical_compare, который делает почти то же самое, за исключением того, что он возвращает истину, если первая последовательность лексикографически меньше второй, и ложь в противном случае.

strcpy копирует последовательности кодаединицы.Вместо этого вы можете использовать алгоритм copy в стандартной библиотеке.

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

В отличие от функций str*, алгоритмы, которые я предложил, используют два итератора для разграничения последовательностей кодовых единиц;один указывает на первый элемент последовательности, а другой указывает на позицию после последнего элемента последовательности.Функции str* принимают только указатель на первый элемент, а затем предполагают, что последовательность продолжается до первой единицы кода с нулевым значением.Когда вы реализуете свой собственный шаблонный строковый класс, лучше всего также отойти от явного соглашения о нулевом завершении и просто предложить метод end(), который обеспечивает правильную конечную точку для вашей строки.

2 голосов
/ 31 декабря 2011

Причина, по которой вы не можете использовать strcmp, strcpy или strlen, заключается в том, что они работают со строками, длина которых указывается завершающим нулевым байтом.Поскольку ваши строки могут содержать ноль байтов внутри них, вы не можете использовать эти функции.

Я бы просто написал именно то, что вы хотите.То, что вы хотите, зависит от того, что вы пытаетесь сделать.

1 голос
/ 31 декабря 2011

В UTF16 вы можете видеть байты, равные '\0' в середине строки; strcmp, strcpy и strlen будут возвращать неверные результаты для подобных строк, поскольку они работают в предположении, что строки заканчиваются нулем.

Вы можете использовать копирование, равенство и расстояние от STL для копирования, сравнения и вычисления длины на основе шаблонных итераторов.

...