Прежде всего, 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()
, который обеспечивает правильную конечную точку для вашей строки.