Question

I sit around and think about whether or not I should be using const char* or const std::string& pretty often when I'm designing class interfaces and when it comes down to it, I often feel like there's 6 in one hand with half a dozen in the other.

Take the following two function prototypes:

void foo(const char* str);
void foo(std::string str);

If the foo function were to store a string, I would say the second is a better option due to the ability to pass a string and utilize move semantics where possible. However, if foo only needed to read the string, would the const char* solution be better?

On a performance perspective, a temporary std::string wouldn't need to be created. However, calling the function with an already existing string as an argument looks obtrusive: foo(mystr.c_str()). Worse yet, if more advanced operations need to be done on the array at some point down the road or if a copy should be stored, the interface then has to change.

So my questions is this:

Are there well defined, either personal or otherwise, conventions that rule when std::string or const char* is a better choice? Furthermore, when starting a new project, is it best to be consistent with usage or just take whichever one fits the current chunk of code best?

Was it helpful?

Solution

const char* is a throwback to C. I'd say that in decent C++, about the only use for it is in extern "C" APIs.

std::string has a number of advantages:

  1. It provides a constant-time size() function. Discovering the length of a const char* takes linear time.

  2. It is guaranteed to be valid. A const char* has to be checked for being null, and it is entirely possible to pass incorrect data - data missing a null terminator. Such an occurrence is pretty much guaranteed to result in a crash or worse.

  3. It is compatible with standard algorithms.

If you're worried about performance impacts of having to create a std::string to call the function, consider taking the approach the standard library uses - change the function to take a pair of iterators instead. You can then provide a convenience overload taking a const std::string& delegating to the iterator-pair one.

OTHER TIPS

Just a few notes from personal experience. If you are working on a c++ project (as per the tag you added) stick to the std::string provided as much as you can. Do not try to reinvent the most basic of all structures, the almighty string. I saw several projects where they reinvented the basic string and afterwards spent months fine tuning it.

In case of your c++ project from the moment you have introduced a char* variable you fall back to standard C functions, such as strlen() and strcpy (just to name two ...). And from this point your project starts turning in a mess, with hand managed memory allocation, etc...

In case you need to interact with third party libraries which accept const char* as their parameter (and I suppose you trust those libraries - ie: you trust they do not const_cast away the constness to do evil things with your poor string) you can use std::string::c_str() to get the const char* out of your string.

In case you need to interact with libraries which have methods accepting char* I highly recommend you take a copy of your string's c_str() and use that as the ingoing parameter to the library (of course, do not forget to delete the extra copy).

Beside of these extra points I just subscribe to all three points from Angew's response.

std::string should always be the first choice in c++. To avoid extra copy overhead you should almost always pass argument as reference and const reference whereever and whenever possible.

In that case your function signature would become like this

void foo(std::string &str);

and like this if argument is const

void foo(const std::string &str);

There are benifits of this const key word that you can look here

Instead of using

void foo(std::string str); 

you could use

void foo(const std::string& str);

which would be equivalent to

void foo(const char* str);

in terms of usage, because no memory is allocated when passing a reference. But for strings in C++ I'd definitely use std::string. For random data or C compatible interfaces I wouldn't.

std::string is better than using raw char * where you have to manage allocations, deallocations and size related issue to be careful for any overflow, underflow, that you are not crossing the size boundary. Whereas std::string these are all taken care of through abstraction

If you want better handling of your say data (in your case it will be string) i'd say go with char *. It will give you better access to your string and memory utilization. But if you don't have to worry about performance and memory management issue than you can use std::string easily.

Well, I would rephrase your question slightly. You should ask when character array should be used instead of std::string.

It is because you should always use string unless you cannot use it. So situations where you should use characters array instead of string:

  1. Using APIs that supports C so you cannot use string.
  2. Passing data between exe and dll. It is not recommended to exchange data types that have constructor and/or destructor between exe and dll

If you worry about performance, after compilation with all optimizations enabled string becomes similar to character array, maybe gives even better performance in some cases, for example if you need to get number of characters it contains.

Also about performance, you can always pass by reference, as other answers mentioned, in case you have to pass a pointer to character array, you can use method c_str() which returns const pointer to first character, if you have to pass pointer (not const pointer) you can (but actually shouldn't) pass it like this: &str[0].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top