2010-10-19 3 views
5

Это почти весь вопрос. Боюсь, я не знаю шаблонов (или C++, действительно), но я знаю алгоритмы и структуры данных (даже некоторые ООП! :). Во всяком случае, чтобы сделать вопрос более точным, подумайте о том, что я хотел бы быть частью ответа (среди прочего, я не знаю заранее).Как класс string в C++ std работает

  1. Почему это кодируется как шаблон?
  2. Как работает шаблон?
  3. Как это распределить память?
  4. Почему (не) лучше, чем простые массивы символов с нулевым завершением?

спасибо.

+10

У вас есть книга на C++? Если вы не знаете, как работают шаблоны, спрашивая, почему класс использует их, кажется, что я был в темноте для меня. – GManNickG

+0

http://www.cplusplus.com/reference/string/ - хорошее начало. – Tristan

+0

Не так ли сложно объяснить? Конечно, вы должны знать, чтобы объяснить это ясно ... Держу пари, кто-то здесь может сделать это, не покровительствовав. Интересно, действительно, что произойдет, если мои ученики придут ко мне с таким вопросом, и я просто сказал: «Пойди, узнай сам!» Вы, ребята, ... :) –

ответ

15
  1. std::string на самом деле в typedef к std::basic_string<char>, и в этом заключается ответ на выше вашего # 1. Его шаблон, чтобы сделать basic_string, работает практически со всем. , unsigned char, wchar_t, pizza, что угодно ... string сам по себе просто программист, который использует char как тип данных, так как это часто требуется.

  2. Unanswerable as ask. Если вы что-то смущены, попробуйте немного сузить его.

  3. Есть два ответа.Один, с точки зрения прикладного уровня, все объекты basic_string используют объект allocator для выполнения фактического распределения. Методы распределения могут варьироваться от одной реализации к следующей и для разных параметров шаблона, но на практике они будут использовать new на нижних уровнях для распределения & управления содержащимся ресурсом.

  4. Его лучше, чем простые массивы символов по самым разным причинам.

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

    • В этой связи string можно рассматривать как своего рода умный указатель. По тем же причинам, почему интеллектуальные указатели лучше, чем исходные указатели, string s лучше, чем массивы raw char.

    • Тип безопасности. Это может показаться немного запутанным, но string правильно использует лучшую безопасность типа, чем буферы символов. Рассмотрим общий сценарий:

 

#include <string> 
#include <sstream> 
using namespace std; 

int main() 
{ 
    const char* jamorkee_raw = "jamorkee"; 

    char raw_buf[0x1000] = {}; 
    sprintf(raw_buf, "This is my string. Hello, %f", jamorkee_raw); 

    const string jamorkee_str = "jamorkee"; 
    stringstream ss; 
    ss << "This is my string. Hello " << jamorkee_str; 
    string s = ss.str(); 
} 

вопрос безопасности типа поднят в приведенном выше с использованием исходного буфера обугленного даже не представляется возможным при использовании string наряду с потоками.

+0

Что такое форматирование?!?! Graaaargh! –

+2

+1 для удивительного ответа. Простой, но не слишком простой! –

+0

Что-то делать с блоками кода после списков. :/Вот моя попытка, вам не нужно ее хранить. – GManNickG

0

Хороший бесплатный онлайн-ресурс «Думая на C++» Брюса Эккеля, сайт которого находится здесь: http://mindview.net/Books/TICPP/ThinkingInCPP2e.html.

Второй том его бесплатной книги отражен здесь: http://www.smart2help.com/e-books/ticpp-2nd-ed-vol-two/#_ftnref14. Третья глава посвящена классу строк, почему это шаблон и почему он полезен.

+0

Спасибо за ресурс. Я не спрашиваю о том, как его использовать, просто как он реализован на самом низком уровне. –

2
  1. string не шаблон, string является конкретизацией шаблона basic_string класса для char. Это шаблон, так что, например, вы можете typedef wstring, который специализируется на широких символах и использует все тот же код для инкапсулированного значения.

  2. См. Комментарий @ Gman. Compile-time Повторное использование кода, сохраняя при этом возможность выборочного специального случая, является основным обоснованием для шаблонов.

  3. Выполнение зависит. Некоторые делают выделение одного экземпляра, с копией при записи. Некоторые используют встроенный буфер для небольших строк и выделяют из кучи только после достижения определенного размера. Я предлагаю вам изучить, как это работает на вашем компиляторе, идя по конструктору и следующему коду в <string>, так как это поможет вам понять 2. руки, что является более ценным, чем просто чтение об этом (хотя книга или другое чтение это отличная идея для введения шаблонов).

  4. Потому что const char* и CRT, который поддерживает его, является фермой ошибок для неосторожного. Ознакомьтесь со всеми вещами, которые вы получаете бесплатно с std::string. Плюс a whole bunch of Standard C++ algorithms, которые работают с итераторами string.

7

Довольно быстро (и поэтому, вероятно, неполный) выстрелил в ответе на некоторые вопросы:

  1. Почему закодированы в качестве шаблона?

Шаблоны предоставляют возможность функциям класса работать с произвольными типами данных. Например, класс шаблонов basic_string<> может работать на char единицах (это то, что делает typedef std::string) или wchar_t единиц (std::wstring) или любого типа POD. Использование чего-то другого, кроме char, или wchar_t необычно (std::vector<> скорее всего будет использоваться), но возможность существует.

  1. Как это распределяет память?

Это не указывается стандартом. Фактически, шаблон basic_string<> позволяет использовать произвольный распределитель для фактического распределения памяти (но не определяет, в каких точках могут потребоваться выделения). Некоторые реализации могут хранить короткие строки в действительных членах класса и распределять динамически только тогда, когда строки растут за пределами определенного размера. Запрошенный размер может быть именно тем, что нужно для хранения строки или может быть кратным размеру, чтобы обеспечить рост без перераспределения.

Дополнительная информация украдена из another SO answer:

Scott Meyer's book, Effective STL, есть глава по реализации станд :: струнные, что порядочный обзор общих изменений: «Пункт 15: быть в курсе изменений в реализациях строки».

Он говорит о 4 варианте:

  • нескольких вариаций на реф подсчета реализации (обычно известной как копирование при записи) - когда объект строки копируется без изменений, RefCount увеличивается на единицу, но реальная строку данных нет. Оба объекта указывают на одни и те же refcounted данные, пока один из объектов не изменяет его, вызывая «копирование при записи» данных. Существуют вариации, в которых хранятся вещи, такие как refcount, locks и т. Д.

  • реализация «короткой строки оптимизации». В этом варианте объект содержит обычный указатель на данные, длину, размер динамически распределенного буфера и т. Д. Но если строка достаточно короткая, она будет использовать эту область для хранения строки вместо динамического выделения буфера

  1. Почему (не) лучше, чем простые массивы символов с нулевым завершением?

Один из способов string класса лучше, чем просто нулем массива является то, что класс управляет памятью требуется, поэтому дефекты, связанные с ошибками выделения или обгонных концом выделенных массивов снижается. Другая (возможно, незначительная) выгода заключается в том, что вы можете хранить «нулевые» символы в строке. Недостатком является то, что, возможно, некоторые накладные расходы - особенно, что вы в значительной степени должны полагаться на динамическое распределение памяти для класса строк. В большинстве сценариев, которые, вероятно, не являются серьезной проблемой, на некоторых настройках (например, в встроенных системах) это может быть проблемой.

+0

Nice дополнения. Благодарю. –

+0

Не так быстро, не так неполно. Хороший ответ. :) –

+0

Я собирался попытаться что-то сказать о том, «Как работает шаблон?» вопрос, но я решил пнуть. –

2

Почему это кодируется как шаблон?

Несколько человек дали ответ, что с std::basic_string быть шаблоном означает, что вы можете иметь как std::basic_string<char> и std::basic_string<wchar_t>. То, что никто не объяснил, - это то, почему C и C++ имеют несколько типов символов.

C, особенно в ранних версиях, был минималистичен в отношении типов данных. Почему есть bool, когда целые числа 0 и 1 работают нормально? И почему существуют разные типы для «байта» и «символ», когда они оба являются 8 битами?

Проблема в том, что 8 бит ограничивают вас 256 символами, что подходит для алфавитного языка, такого как английский или русский, но нигде не достаточно для японского или китайского. И теперь у нас есть Unicode с его 21-битными кодовыми точками. Но char не может быть расширен до 16 или 32 бит, потому что предположение о том, что= байт настолько укоренилось. Таким образом, мы получили отдельный тип для «широких символов».

Но теперь у нас есть проблема, что wchar_t является UTF-32 на Linux, но UTF-16 на Windows. И чтобы решить , проблема в следующей версии стандарта C++ добавит типы char16_t и char32_t (и соответствующие типы строк).

Смежные вопросы