Использование необработанной строки
Да, иногда это действительно удается. При использовании массивов const char *, char, выделенных в стеке, и строковых литералов вы можете сделать это таким образом, чтобы память не выделялась вообще.
Написание такого кода часто требует большего мышления и осторожности, чем использование строки или вектора, но с помощью надлежащих методов это можно сделать. При правильной технике код может быть безопасным, но вам всегда нужно быть уверенным, что при копировании в char [] у вас либо есть гарантии относительно длины копируемой строки, либо вы проверяете и обрабатываете слишком большие строки изящно. Невыполнение этого требования и дало семейству функций strcpy репутацию небезопасных.
Как шаблоны могут помочь в написании безопасных буферов символов
Что касается безопасности буферов char [], могут помочь шаблоны, поскольку они могут создавать инкапсуляцию для обработки размера буфера за вас. Подобные шаблоны реализованы, например, Microsoft, чтобы обеспечить безопасную замену strcpy. Пример здесь извлечен из моего собственного кода, в реальном коде гораздо больше методов, но этого должно быть достаточно, чтобы передать основную идею:
template <int Size>
class BString
{
char _data[Size];
public:
BString()
{
_data[0]=0;
_data[Size-1]=0;
}
const BString &operator = (const char *src)
{
strncpy(_data,src,Size-1);
return *this;
}
operator const char *() const {return _data;}
};
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
return dst = src;
}