char* vs std::string in c++ [closed]
When should I use std::string
and when should I use char*
to manage arrays of char
s in C++?
It seems you should use char*
if performance(speed) is crucial and you're willing to accept some of a risky business because of the memory management.
Are there other scenarios to consider?
Solution 1:
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.
Solution 2:
You can pass std::string
s 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.
Solution 3:
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;
}