Почему в С++ следует использовать std::string вместо строк в стиле c?

«Всегда следует использовать std::string вместо строк в стиле c(char * )" - это совет, который подходит почти для каждого исходного кода, размещенного здесь. Несмотря на то, что совет, несомненно, хорош, фактически рассматриваемые вопросы не позволяют подробно остановиться на его аспекте почему?. Этот вопрос должен служить заполнителем для того же самого.

Хороший ответ должен охватывать следующие аспекты (подробно):

  1. Почему в С++ следует использовать std::string вместо строк в стиле c?
  2. Каковы недостатки (если таковые имеются) практики, упомянутой в #1?
  3. Каковы сценарии, когда совет, противоположный упомянутому в #1, является хорошей практикой?

person Alok Save    schedule 05.04.2012    source источник
comment
Я планирую пометить этот c++-Faq и обсудить то же самое в C++ Lounge в ближайшее время.   -  person Alok Save    schedule 05.04.2012
comment
Об этом еще спрашивают в 2012 году?! Кроме того, когда совет использовать std::string всегда не сопровождается рационализацией?   -  person Karl Knechtel    schedule 05.04.2012
comment
@KarlKnechtel: Извините, похоже, я новичок в C ++, в отличие от вас :) Однако я бы потрудился прочитать весь вопрос и понять его цель, а не просто прочитать заголовок перед комментированием.   -  person Alok Save    schedule 05.04.2012


Ответы (6)


  1. std::string управляет своей собственной памятью, поэтому вы можете легко копировать, создавать и уничтожать их.
  2. Вы не можете использовать свой собственный буфер как std::string.
  3. Вам нужно передать строку c / буфер чему-то, что ожидает получить право собственности на буфер, например, сторонней библиотеке C.
person Michael Anderson    schedule 05.04.2012

Что ж, если вам просто нужен массив символов, std::string дает небольшое преимущество. Но признайтесь, как часто это бывает? Оборачивая массив символов дополнительными функциями, такими как std::string, вы получаете как мощность, так и эффективность для некоторых операций.

Например, для определения длины массива символов требуется «подсчет» символов в массиве. Напротив, std::string обеспечивает эффективную работу для этой конкретной задачи. (см. https://stackoverflow.com/a/1467497/129622)

  1. Для мощности, эффективности и здравомыслия
  2. Больший объем памяти, чем «просто» массив символов
  3. Когда вам просто нужен массив символов
person ybakos    schedule 05.04.2012

3) Совет всегда использовать string, конечно, нужно воспринимать с долей здравого смысла. Строковые литералы — это const char[], и если вы передаете литерал функции, которая принимает const char* (например, std::ifstream::open()), нет абсолютно никакого смысла оборачивать его в std::string.

person Steve Jessop    schedule 05.04.2012

char* в основном является указателем на символ. То, что делает C, часто заставляет этот указатель указывать на первый символ в массиве.

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

Причины использовать char* вместо std::string:

C backwards-compatibility.
Performance (potentially).
char*s have lower-level access.

Причины использовать std::string вместо char*:

Much more intuitive to use.
Better searching, replacement, and manipulation functions.
Reduced risk of segmentation faults.

Пример :

char* должен использоваться в сочетании либо с массивом символов, либо с динамически выделяемым массивом символов. В конце концов, указатель бесполезен, если он на самом деле не указывает на что-то. Это в основном используется в программах C:

char somebuffer[100] = "a string";
char* ptr = somebuffer;  // ptr now points to somebuffer
cout << ptr; // prints "a string"
somebuffer[0] = 'b';  // change somebuffer
cout << ptr;  // prints "b string" 

обратите внимание, что когда вы меняете 'somebuffer', 'ptr' также меняется. Это связано с тем, что в этом случае somebuffer является фактической строкой. ptr просто указывает/ссылается на него.

С std::string это менее странно:

std::string a = "a string";
std::string b = a;
cout << b;  // prints "a string"
a[0] = 'b';  // change 'a'
cout << b;  // prints "a string" (not "b string") 

Здесь вы можете видеть, что изменение «a» не влияет на «b», потому что «b» — это фактическая строка.

Но на самом деле главное отличие состоит в том, что с массивами char вы отвечаете за управление памятью, тогда как std::string делает это за вас. В C++ очень мало причин использовать массивы символов вместо строк. В 99 случаях из 100 вам лучше использовать строку.

Пока вы полностью не разберетесь в управлении памятью и указателях, просто избавьте себя от головной боли и используйте std::string.

person SandBag_1996    schedule 10.08.2012
comment
Я сомневаюсь в утверждении о лучшей производительности струн C. Он действительно требует меньше памяти, что может иметь решающее значение, если у вас много маленьких строк (например, при синтаксическом анализе или биоинформатике, где std::string может быть непомерно высоким). - person Konrad Rudolph; 11.08.2012
comment
Использование char* дает вам больший контроль над тем, что происходит за кулисами, что означает, что вы можете настроить производительность, если вам нужно. - person SandBag_1996; 11.08.2012

Почему в С++ следует использовать std::string вместо строк в стиле c?

Основная причина в том, что это освобождает вас от управления временем жизни строковых данных. Вы можете просто рассматривать строки как значения и позволить компилятору/библиотеке беспокоиться об управлении памятью.

Ручное управление выделением памяти и временем жизни утомительно и чревато ошибками.

Каковы недостатки (если они есть) практики, упомянутой в № 1?

Вы отказываетесь от тонкого контроля над выделением памяти и копированием. Это означает, что в конечном итоге вы получаете стратегию управления памятью, выбранную поставщиком вашей цепочки инструментов, а не выбранную в соответствии с потребностями вашей программы.

Если вы не будете осторожны, вы можете получить много ненужного копирования данных (в реализации без подсчета ссылок) или манипуляции со счетчиком ссылок (в реализации с подсчетом ссылок)

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

Каковы сценарии, в которых противоположность совету, упомянутому в № 1, является хорошей практикой?

У разных людей будут разные мнения по этому поводу, но ИМО

  • Для аргументов функции передача строк в "const char *" является хорошим выбором, так как это позволяет избежать ненужного копирования/пересчета ссылок и дает вызывающей стороне гибкость в отношении того, что они передают.
  • Для вещей, используемых во взаимодействии с другими языками, у вас нет другого выбора, кроме как использовать строки в стиле c.
  • Когда у вас есть известный предел длины, может быть быстрее использовать массивы фиксированного размера.
  • При работе с очень длинными строками может быть лучше использовать конструкцию, которая определенно будет пересчитана, а не скопирована (например, массив символов, обернутый в shared_ptr), или вообще использовать другой тип структуры данных.
person plugwash    schedule 26.07.2016

В общем, вы всегда должны использовать std::string, так как он менее подвержен ошибкам. Имейте в виду, что накладные расходы памяти для std::string значительны. Недавно я провел несколько экспериментов с накладными расходами std::string. В общем это около 48 байт! Статья находится здесь: http://jovislab.com/blog/?p=76.

person asanoki    schedule 13.04.2012
comment
Жаль, что небольшая оптимизация строк — это здорово. - person Puppy; 13.04.2012
comment
Все зависит от реализации. Но на практике, без отладки, подслушивание должно быть незначительным. - person Etienne de Martel; 13.04.2012
comment
Это важно. С -O2 и без -g G++ по-прежнему занимает 24 байта для байтовой строки. Я полагаю, то же самое для Visual Studio. - person asanoki; 18.04.2012
comment
@asanoki: Используя мой код на ideone.com/ynJhF (выделение 1000000 строк общей длиной 7 502 096 символов), VC++10 выделил 38 712 КБ для char* и unique_ptr и выделил 27 428 КБ для строки. (Это 41% экономии). В G++ 4.5.4 для char* и unique_ptr было выделено 23 052 КБ, а для строки — 33 832 КБ (это 47% дополнительного пространства). - person Mooing Duck; 11.08.2012