• std::string — как правило, если не указано противное.
• QString, AnsiString/UnicodeString и прочие — в соответствующих фреймворках, обычно очень близко к интерфейсным функциям.
• char* — практически не используется в реальном коде. В основном для оптимизации, если есть собственное управление памятью. Довелось как-то в собственном разборщике XML (работает в 2,5 раза медленнее рекордсмена, pugixml. Зато даже это в разы быстрее Excel’я, пространства имён «из коробки», расход памяти мизерный и программирование простейшее.)
Зато по-чёрному используется его const-аналог.
• const char*. Это может быть одинокий const char* + нуль-терминированная строка, или указатель+длина, или указатель на начало + указатель за конец.
1. Если ожидается, что в функцию будем передавать строковый литерал.
void writeEnum(st::Stream& st, int value, const char* names[]) {}
enum class Letter { A, B, C, …, Z, NN };
const char* natoNames[static_cast<int>(Letter::NN)] = { "alpha", "bravo", "charlie", … };
writeEnum(someStream, static_cast<int>(Letter::E), natoName);
2. Если операцию со строкой можно произвести «на месте», не заводя новую память: (trim, как известно,— обрезка пробелов в начале и конце)
void trim(const char*& beg, const char*& end);
3. Если структура данных паразитирует на чужих строках, не заводя своей памяти. Особенно если конструкция строк неизвестна (например, при передаче данных из плагина в плагин).
struct ParasiteString { const char *beg, *end; };
4. В библиотеках, если они реально настолько компактные, что нет нужды обязательно подключать жирный STL.
• char[] — только как оптимизация, когда предельная длина строки известна и невелика.
wchar_t* myFtos(double value, wchar_t* buf, const FloatFormat& format) {}
wchar_t buf[100];
myFtos(100.500, buf, FloatFormat::NICE);