char* vs std::string in c++ [closed] char* vs std::string in c++ [closed] arrays arrays

char* vs std::string in c++ [closed]


My point of view is:

  • Never use char * if you don't call "C" code.
  • Always use std::string: It's easier, it's more friendly, it's optimized, it's standard, it will prevent you from having bugs, it's been checked and proven to work.


You can pass std::strings by reference if they are large to avoid copying, or a pointer to the instance, so I don't see any real advantage using char pointers.

I use std::string/wstring for more or less everything that is actual text. char * is useful for other types of data though and you can be sure it gets deallocated like it should. Otherwise std::vector<char> is the way to go.

There are probably exceptions to all of this.


Raw string usage

Yes, sometimes you really can do this. When using const char *, char arrays allocated on the stack and string literals you can do it in such a way there is no memory allocation at all.

Writing such code requires often more thinking and care than using string or vector, but with a proper techniques it can be done. With proper techniques the code can be safe, but you always need to make sure when copying into char [] you either have some guarantees on the lenght of the string being copied, or you check and handle oversized strings gracefully. Not doing so is what gave the strcpy family of functions the reputation of being unsafe.

How templates can help writing safe char buffers

As for char [] buffers safety, templates can help, as they can create an encapsulation for handling the buffer size for you. Templates like this are implemented e.g. by Microsoft to provide safe replacements for strcpy. The example here is extracted from my own code, the real code has a lot more methods, but this should be enough to convey the basic idea:

template <int Size>class BString{  char _data[Size];  public:  BString()  {    _data[0]=0;    // note: last character will always stay zero    // if not, overflow occurred    // all constructors should contain last element initialization    // so that it can be verified during destruction    _data[Size-1]=0;  }  const BString &operator = (const char *src)  {    strncpy(_data,src,Size-1);    return *this;  }  operator const char *() const {return _data;}};//! overloads that make conversion of C code easier template <int Size>inline const BString<Size> & strcpy(BString<Size> &dst, const char *src){  return dst = src;}