Почему так много строковых классов перед лицом std :: string?

56

Мне кажется, что многие большие библиотеки C ++ создают свои собственные строковые типы. В коде клиента вы должны либо использовать один из библиотеки ( QString, CString, и fbstringт.д., я уверен , что кто - нибудь может назвать несколько) или сохранить преобразование между стандартным типом и одна библиотека использует (который большую часть времени включает в себя хотя бы один экземпляр).

Итак, есть ли конкретная ошибка или что-то не так std::string(как auto_ptrсемантика была плохой)? Изменилось ли это в C ++ 11?

Тамас Селеи
источник
32
Он называется «Синдром не изобретен здесь».
Cat Plus Plus
10
@CatPlusPlus QString и CString оба предшествовали std :: string.
Gort the Robot
8
@Cat Plus Plus: Этот синдром, похоже, не влияет на класс Java String.
Джорджио
20
@ Джорджио: Java-программисты слишком заняты изобретением обходных путей для языковых недостатков, чтобы беспокоиться о строковых классах (кстати, Android заново изобрел String).
Cat Plus Plus
9
@ Джорджио: Это, вероятно, потому что жестко закодированная поддержка синтаксиса Java java.lang.String(отсутствие перегрузки операторов и т. Д.) Затрудняет использование чего-либо еще.
Механическая улитка

Ответы:

57

Большинство этих больших библиотек C ++ были запущены до того, как std::stringбыли стандартизированы. Другие включают дополнительные функции, которые были стандартизированы поздно или еще не стандартизированы, такие как поддержка UTF-8 и преобразование между кодировками.

Если бы эти библиотеки были реализованы сегодня, они, вероятно, решили бы написать функции и итераторы, которые работают с std::stringэкземплярами.

Бен Фойгт
источник
5
Поддержка UTF-8 стандартизирована начиная с C ++ 98. В таком неудобном и частично определенном для реализации способе, который, кажется, никто не может использовать
AProgrammer
9
@AProgrammer: charгарантированно достаточно большой, чтобы вместить любую кодовую точку UTF-8. AFAIK, это единственная «поддержка», предоставляемая C ++ 98.
Бен Фойгт
4
@AProgrammer: эта поддержка действительно бесполезна.
DeadMG
4
@AProgrammer Эта локаль, возможно, не работает, поскольку wchar_tона недостаточно велика для представления всех кодовых точек Unicode Кроме того, была целая дискуссия о том, что UTF-16 считается вредным, когда был сделан очень убедительный аргумент, что UTF-8 должен использоваться исключительно
Конрад Рудольф
6
@KonradRudolph, там не работает система локалей (определение wchar_t «достаточно широк для любого поддерживаемого набора символов»); системы, имеющие 16-битный wchar_t, одновременно обязались не поддерживать Unicode. Что ж, виновником является Unicode, который сначала гарантировал, что он никогда не будет использовать кодовые точки, требующие более 16 бит, затем системы, фиксирующие 16 битов wchar_t, а затем переключение Unicode, чтобы потребовать более 16 бит.
AProgrammer
39

Строка - это большое затруднение C ++.

Первые 15 лет вы вообще не предоставляете строковый класс - вынуждаете каждого компилятора на каждой платформе и каждого пользователя создавать свои собственные.

Затем вы делаете что-то, что сбивает с толку, будь то API-интерфейс для манипулирования всей строкой или просто контейнер символов STL, с некоторыми алгоритмами, которые дублируют алгоритмы в std :: Vector или отличаются.

Там, где очевидная строковая операция, такая как replace () или mid (), включает в себя такой беспорядок итераторов, что вам нужно ввести новое ключевое слово 'auto', чтобы сохранить соответствие оператора на одной странице, и побуждает большинство людей отказаться от всего языка. ,

И тогда у вас есть Unicode 'поддержка' и std :: wstring, что просто так .....

Спасибо, я чувствую себя намного лучше.

Мартин Беккет
источник
12
@DeadMG - да, и он был стандартизирован в 1998 году, через 15 лет после его изобретения и через 6 лет после того, как даже MSFT использовал его. Да, итераторы - это полезный способ заставить массив и список выглядеть одинаково. Как вы думаете, они являются очевидным способом манипулирования строками?
Мартин Беккет
3
C с классами был изобретен в 1983 году. Не C ++. Единственными стандартными библиотеками являются те, которые определены Стандартом, что, как ни странно, может произойти только при наличии Стандарта, поэтому самой ранней возможной датой для любой стандартной библиотеки является 1998 год. Итераторы можно считать точно равными индексам, но строго типизированными. Я за то, что итераторы отстой по сравнению с диапазонами, но это не совсем так std::string. Отсутствие класса Стринг в 1983 году не оправдывает, что сейчас их больше.
DeadMG
8
Я думал, что iostreams были большим смущением C ++ ...
Даг Т.
18
@DeadMG Люди использовали что-то под названием «C ++» в течение многих лет до 1998 года. Я написал свою первую программу с использованием чего-то под названием «C ++» в 1985 году. Если вы хотите сказать, что это не «настоящий» C ++, это нормально, но до этого мы писали код и должны были откуда-то получить строковый класс. После того, как у нас были эти унаследованные кодовые базы, мы не могли точно выбросить их или переписать с нуля, когда получили стандарт. Теперь то, что должно было случиться, - это то, что должен быть класс строки, поставляемый с cfront.
Gort Робот
8
@DeadMG - Если бы никто не использовал язык, пока у него не было сертификата ISO, ни один язык не использовался бы, так как он никогда не достигнет ISO. Не существует стандарта ISO для ассемблера x86, но я рад использовать платформу
Мартин Беккет
32

На самом деле ... есть несколько проблем std::string, и да, это немного лучше в C ++ 11, но давайте не будем забегать вперед.

QStringи CStringявляются частью старых библиотек, поэтому они существовали до стандартизации C ++ (во многом как SGI STL). Таким образом, они должны были создать класс.

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

Другие проблемы, которые не были вызваны здесь (en vrac):

  • в C ++ 03 не обязательно, чтобы хранилище было непрерывным, что потенциально затрудняло взаимодействие с C. C ++ 11 исправляет это.
  • std::string не кодирует и не имеет специального кода для UTF-8, легко хранить в нем строку UTF-8 и непреднамеренно ее повреждать
  • std::stringИнтерфейс раздут , многие методы могли бы быть реализованы как свободные функции, а многие дублированы для соответствия как интерфейсу на основе индекса, так и интерфейсу на основе итератора.
Матье М.
источник
5
Касательно # 1 - C ++ 03 21.3.6 / 1 гарантирует, что c_str()возвращает указатель на непрерывное хранилище, что обеспечивает некоторую совместимость с Си. Однако вы не можете изменить указанные данные. Типичные обходные пути включают использование vector<char>.
Джон Диблинг
@JohnDibling: Да, и есть еще одно ограничение: оно может повлечь за собой копию во вновь выделенном хранилище (Стандарт не говорит, что не должен). Конечно, C ++ 11 также не препятствует копированию, но, поскольку вы можете просто сделать &s[0]это, это уже не имеет значения :)
Matthieu M.
1
@MatthieuM .: Указатель, полученный с помощью, &s[0]может не указывать на NUL-оканчивающуюся строку (если c_str()не был вызван с момента последней модификации).
Бен Фойгт
2
@Matthieu: другой буфер не допускается. c_str()Msgstr " Возвращает: указатель pтакой, что p + i == &operator[](i)для каждого iв [0,size()]".
Бен Фойгт
3
Стоит также отметить, что никто в здравом уме больше не использует MFC, поэтому трудно утверждать, что CString является строковым классом в современном C ++.
DeadMG
7

Помимо приведенных здесь причин, есть еще одна - двоичная совместимость . Авторы библиотек не контролируют, какую std::stringреализацию вы используете и имеет ли она ту же структуру памяти, что и их.

std::stringявляется шаблоном, поэтому его реализация взята из ваших локальных заголовков STL. Теперь представьте, что вы используете локальную версию STL с оптимизированной производительностью, полностью совместимую со стандартом. Например, вы, возможно, решили использовать статический буфер в каждом, std::stringчтобы уменьшить количество динамических выделений и пропусков кэша. В результате компоновка памяти и / или размер вашей реализации отличается от библиотеки.

Если отличается только компоновка, некоторые std::stringвызовы функций-членов в экземплярах, переданных из библиотеки в клиент, или наоборот, могут завершиться ошибкой в ​​зависимости от того, какие элементы были смещены.

Если размер также отличается, все типы библиотек, имеющие std::stringчлен, будут иметь разный размер при проверке в библиотеке и в клиентском коде. Для элементов данных, следующих за std::stringэлементом, также будут смещены смещения, и любой метод прямого доступа / встроенного доступа, вызванный из клиента, будет возвращать мусор, несмотря на то, что при отладке библиотеки он выглядит «нормально».

Итог - если библиотека и клиентский код скомпилированы против разных std::stringверсий, они будут просто отлично связываться, но это может привести к некоторым неприятным, трудным для понимания ошибкам. Если вы измените свою std::stringреализацию, все библиотеки, выставляющие элементы из STL, должны быть перекомпилированы, чтобы соответствовать std::stringмакету клиента . И поскольку программисты хотят, чтобы их библиотеки были надежными, вы редко будете видеть их std::stringгде-либо открытыми.

Чтобы быть справедливым, это относится ко всем типам STL. IIRC у них нет стандартизированного расположения памяти.

gwiazdorrr
источник
2
Вы должны быть * nix программистом. Бинарная совместимость C ++ не одинакова на всех платформах, и, в частности, в Windows классы NO, содержащие элементы данных, переносимы между компиляторами.
Бен Фойгт
(Я имею в виду, кроме типов POD, и даже тогда необходимы явные требования к упаковке)
Бен Фойгт
1
Спасибо за ввод, хотя я не говорю о другом компиляторе, я говорю о другом STL.
gwiazdorrr
1
+1: ABI - это огромная причина для создания собственной версии класса, предоставляемого компилятором. Только для этого я хотел бы, чтобы это был принятый ответ.
Томас Эдинг
6

Есть много ответов на этот вопрос, но вот некоторые из них:

  1. Наследие. Многие строковые библиотеки и классы были написаны до существования std :: string.

  2. Для совместимости с кодом на C. Библиотека std :: string - это C ++, где также есть другие строковые библиотеки, которые работают с C и C ++.

  3. Избегать динамических распределений. Библиотека std :: string использует динамическое размещение и может не подходить для встроенных систем, прерываний или кода, связанного с в реальном времени, или для низкоуровневой функциональности.

  4. Шаблоны. Библиотека std :: string основана на шаблонах. До недавнего времени многие компиляторы C ++ имели плохо работающую или даже некорректную поддержку шаблонов. К сожалению, я работаю в отрасли, которая использует множество пользовательских инструментов, и один из наших наборов инструментов от крупного игрока в отрасли «официально» не поддерживает 100% C ++ (с ошибочными шаблонами и т. Д.).

Вероятно, есть еще много веских причин.

Adisak
источник
2
«Совсем недавно», что означает «Прошло десять лет с тех пор, как даже Visual Studio оказал им достаточно разумную поддержку»?
DeadMG
@DeadMG - Visual Studio - не единственный несовместимый компилятор в мире. Я работаю в видеоиграх, и мы часто работаем над пользовательскими компиляторами для невыпущенных аппаратных платформ (это происходит каждые несколько лет в циклах консоли или при появлении нового оборудования). «Довольно недавно» означает сегодня - в настоящее время некоторые компиляторы не поддерживают шаблоны хорошо. Я не могу быть конкретным, не нарушая NDA, но в настоящее время я работаю на платформе с настраиваемыми наборами инструментов, где поддержка C ++ - особенно соответствие шаблонам - считается "экспериментальной".
Адисак
4

Это в основном о Unicode. Стандартная поддержка Юникода в лучшем случае ужасна, и у каждого есть свои потребности в Юникоде. Например, ICU поддерживает все функции Unicode, которые вы когда-либо могли захотеть, за самым отвратительным интерфейсом автоматически сгенерированного из Java, который вы только можете себе представить, и если вы работаете в Unix, зависание с UTF-16 может быть не вашей идеей хорошее время.

Кроме того, многим людям нужны разные уровни поддержки Unicode - не всем нужны сложные API-интерфейсы для разметки текста и тому подобное. Таким образом, легко понять, почему существует множество строковых классов: стандартный класс - отстой, и у всех есть потребности, отличные от новых, когда никому не удается создать отдельный класс, который может выполнять множество кроссплатформенных приложений с поддержкой Юникода с приятным интерфейсом.

По моему мнению, это в основном вина Комитета C ++ за неправильное предоставление поддержки Unicode - в 1998 или 2003 году, возможно, это было понятно, но не в C ++ 11. Надеюсь, в C ++ 17 они будут лучше.

DeadMG
источник
Здравствуйте, C ++ 20 здесь, угадайте, что случилось с поддержкой Unicode?
Прошедший
-4

Это потому, что у каждого программиста есть, что доказывать, и он чувствует необходимость создать свой собственный, более быстрый класс строк для своей замечательной функции. Обычно это немного излишне и приводит к всевозможным дополнительным преобразованиям строк в моем опыте.

Чед Стюарт
источник
7
Если бы это было так, я бы ожидал увидеть подобное количество реализаций String в таких языках, как Java, где хорошая реализация была доступна с самого начала.
Билл К
@BillK Java String является окончательным, поэтому вы должны поместить новую функциональность в другом месте.
И моя точка зрения заключается в том, что, даже будучи окончательным, за 20 лет я никогда не видел, чтобы кто-то писал собственную реализацию строк (ну, я пытался улучшить производительность конкатенации строк, но оказалось, что java НАМНОГО умнее в строке + строке, чем вы » Представляю)
Билл К
2
@ Билл: Это может быть связано с другой культурой. C ++ привлекает тех, кто хочет понять детали низкого уровня. Java привлекает тех, кто просто хочет выполнить работу, используя чужие строительные блоки. (Обратите внимание, что это не утверждение о каком-то конкретном человеке, который выбирает использование того или иного языка, а о соответствующих целях и культуре языков)
Бен Фойгт