const char* vs string

J

Javier

Hello,
in which cases is it better the use of "const char*" to "string" (or
even const string &).
I mean, in STL (http://www.sgi.com/tech/stl/hash_map.html) I see:

hash_map<const char*, int, hash<const char*>, eqstr> months;
months["january"] = 31;

I think it is for the use in calls like function("my string"), but, is
it really necessary to define funcion(const char*) besides
function(const string &) in my public member functions?

I have read that the compiler does too much temporaries variables in
such cases, but is it true?

And what about in:

string mystring = "my string" + string1 + " is " + string2;

or in:

cout << string << " hello" << string2 << " my name is " << string3;

Thanks.
 
I

Ian Collins

Javier said:
Hello,
in which cases is it better the use of "const char*" to "string" (or
even const string &).

Seldom.

The only real reason is interfacing with C code.
I mean, in STL (http://www.sgi.com/tech/stl/hash_map.html) I see:

hash_map<const char*, int, hash<const char*>, eqstr> months;
months["january"] = 31;

I think it is for the use in calls like function("my string"), but, is
it really necessary to define funcion(const char*) besides
function(const string &) in my public member functions?

I have read that the compiler does too much temporaries variables in
such cases, but is it true?

And what about in:

string mystring = "my string" + string1 + " is " + string2;

or in:

cout << string << " hello" << string2 << " my name is " << string3;
What about them? I don't see how these link to your question.
 
J

Javier

Javier said:
Hello,
in which cases is it better the use of "const char*" to "string" (or
even const string &).

Seldom.

The only real reason is interfacing with C code.


hash_map<const char*, int, hash<const char*>, eqstr> months;
months["january"] = 31;
I think it is for the use in calls like function("my string"), but, is
it really necessary to define funcion(const char*) besides
function(const string &) in my public member functions?
I have read that the compiler does too much temporaries variables in
such cases, but is it true?
And what about in:
string mystring = "my string" + string1 + " is " + string2;

Does the compiler create temporaries in this case? Is it important? I
mean, is it better to write?:

string mystring = "my string";
mystring += string1;
mystring += " is ";
mystring += string2;

than:

string mystring = "my string" + string1 + " is " + string2;

Same question.
What about them? I don't see how these link to your question.

Thanks.
 
D

Dizzy

Javier said:
Does the compiler create temporaries in this case? Is it important? I
mean, is it better to write?:

string mystring = "my string";
mystring += string1;
mystring += " is ";
mystring += string2;

than:

string mystring = "my string" + string1 + " is " + string2;

Yes the second version does create temporaries and additional copies (tho
RVO might reduce some there). However, the second version is clearer than
the first one, seems more natural and unless you do that thousands of times
per second it shouldn't matter the additional cost (ie unless your code
profiling points this as a source of bottleneck). Also I think that in the
future with rvalue references and move semantics that overhead will be
eliminated anyway.
 
J

Jacek Dziedzic

Javier said:
Hello,
in which cases is it better the use of "const char*" to "string" (or
even const string &).

Almost never. The only reason I've ever used it when I needed
read/write access to a fixed-size raw buffer of chars that were
copied across processors using MPI without construction/destruction.

The other reasons could be "to be able to compile the program
with a really ancient C++ compiler which does not recognize string"
and "to show people how nasty bugs appear when using char*" <eg>.

HTH,
- J.
 
J

Juha Nieminen

Javier said:
in which cases is it better the use of "const char*" to "string" (or
even const string &).

I would say that "const char*" is ok when you really have
compile-time constant strings, especially if you don't really need
to know their size.

Example:

const char* const KEYWORDS[] =
{ "keyword1", "keyword2", "keyword3", ... };

These are just compile-time constants which are not modified during
the execution of the program, so I would say that it's not really
necessary to have them as std::strings. If at some point you really
need to do some handling with those, it's pretty trivial to create
a std::string from them, like: std::string keyword = KEYWORDS[1];
 
R

Ricardo

void doSomething(std::string& param)
{

}
....

doSomething("DoThat");

doSomething will certainly call std::string constructor, alloc memory,
copy de contents, deallocate and its destructor will do something else
if it has some reference counter...

Why do that if "DoThat" will be stored in the data segement??? I am
not an expert but I am pretty sure you have a performance overhead
which is the price for the convenience...

So, is it never recommended using [const] char* instead of
std::string? I think "never" should be changed to "never if
performance doesn't matter".

Jose Ricardo
 
C

Craig Scott

Seldom.

The only real reason is interfacing with C code.

Actually, it can also matter for C++ code. If you are using shared
libraries, then you need to be aware that the C++ standard does not
guarantee that std::string is safe to use anywhere in a shared
library's interface (it mentions absolutely nothing about shared
libraries at all). This is frequently a surprise to many C++
developers, but Scott Meyers and others give this topic a good
treatment in their various books (sorry, I don't have them on hand at
the moment, but one of the Effective C++/STL books I think). In short,
unless you can guarantee that your code is being compiled with exactly
the same compiler version as the library you are calling and that you
are using exactly the same compiler flags, then the only types safe to
use in the shared library's interface are POD types and pointers (but
it would be potentially unsafe to dereference these pointers).

So for the original poster's question, const char* will always be
portable and is safe to use in a library interface, whereas
std::string might or might not be safe depending on the compiler and
flags used. In real world code, we've found that this does matter and
we have defined our interfaces accordingly. YMMV.
 
R

red floyd

Craig said:
Actually, it can also matter for C++ code. If you are using shared
libraries, then you need to be aware that the C++ standard does not
guarantee that std::string is safe to use anywhere in a shared
library's interface (it mentions absolutely nothing about shared
libraries at all).

Precisely correct in tha tthe Standard doesn't mention shared libraries.
Therefore the C++ standard does not guarantee that const char* is safe
to use anywhere in a shared library's interface either.
 
I

Ian Collins

Craig said:
Actually, it can also matter for C++ code. If you are using shared
libraries, then you need to be aware that the C++ standard does not
guarantee that std::string is safe to use anywhere in a shared
library's interface (it mentions absolutely nothing about shared
libraries at all). This is frequently a surprise to many C++
developers, but Scott Meyers and others give this topic a good
treatment in their various books (sorry, I don't have them on hand at
the moment, but one of the Effective C++/STL books I think). In short,
unless you can guarantee that your code is being compiled with exactly
the same compiler version as the library you are calling and that you
are using exactly the same compiler flags, then the only types safe to
use in the shared library's interface are POD types and pointers (but
it would be potentially unsafe to dereference these pointers).
The same applies to any C++ linkage function as well. If you want to
have maximum compatibility, you have to stick to extern "C" linkage
functions, or choose a compiler that guarantees ABI compatibility.
 
J

James Kanze

Actually, it can also matter for C++ code. If you are using shared
libraries, then you need to be aware that the C++ standard does not
guarantee that std::string is safe to use anywhere in a shared
library's interface (it mentions absolutely nothing about shared
libraries at all).

Strictly speaking, that's true for int as well. If all you're
counting on is what the C++ standard says, then you can't count
on int working in a dynamically linked object either.
This is frequently a surprise to many C++
developers, but Scott Meyers and others give this topic a good
treatment in their various books (sorry, I don't have them on hand at
the moment, but one of the Effective C++/STL books I think). In short,
unless you can guarantee that your code is being compiled with exactly
the same compiler version as the library you are calling and that you
are using exactly the same compiler flags, then the only types safe to
use in the shared library's interface are POD types and pointers (but
it would be potentially unsafe to dereference these pointers).

Not even that: you can't be sure at all about any struct, since
padding may depend on compiler options. For that matter, you
can't be sure about long---I've had the byte order of a long
change from one version of the compiler to the next, and you
certainly can't be sure about pointers, whose size depends on
compiler options.

In practice, there will be a set of options you can play with,
over a set of versions of the compiler.
So for the original poster's question, const char* will always be
portable and is safe to use in a library interface,

Except when the size of a pointer depends on a compiler option
(the usual case today, where all of the platforms I know support
both 32 and 64 bit pointers).

In fact, you're never really portable. The library supplier
should specify the restrictions, but in general, using
std::string entails no more risk than using any other struct.
whereas
std::string might or might not be safe depending on the compiler and
flags used. In real world code, we've found that this does matter and
we have defined our interfaces accordingly.

In the real world, we use std::string and std::vector without
problems, over a variety of compilers and systems.
 
C

Craig Scott

Actually, it can also matter for C++ code. If you are using shared
Strictly speaking, that's true for int as well. If all you're
counting on is what the C++ standard says, then you can't count
on int working in a dynamically linked object either.

Fair enough.

Not even that: you can't be sure at all about any struct, since
padding may depend on compiler options. For that matter, you
can't be sure about long---I've had the byte order of a long
change from one version of the compiler to the next, and you
certainly can't be sure about pointers, whose size depends on
compiler options.

Um, I believe I said exactly the same compiler version and flags. If
you use the same settings on the same compiler for the same platform,
you should get the same byte order, padding, pointer size, etc.

In practice, there will be a set of options you can play with,
over a set of versions of the compiler.


Except when the size of a pointer depends on a compiler option
(the usual case today, where all of the platforms I know support
both 32 and 64 bit pointers).

Agreed. If you change a compiler option which causes a different
pointer size, you should expect things to explode. ;) I think the
main point is to know what compiler and flags were used to build the
shared library you want to use. It is then your responsibility to use
compatible flags for your own code.

In fact, you're never really portable. The library supplier
should specify the restrictions, but in general, using
std::string entails no more risk than using any other struct.

Unless different modules have their own memory heap (we have
encountered situations where some do). Then you run the risk of having
memory allocated in one module and then when you resize the string,
vector, etc in another module the memory needs to be freed in that
module and BOOM! Even if memory is always allocated/deallocated from
the one heap, having std::string, std::vector or any other container
in the interface prevents you from doing some cool stuff like use an
alternate STL implementation in your own code (such as STLport for
improved error checking). But "cool stuff" is just that, not
necessarily "required stuff". ;)

In the real world, we use std::string and std::vector without
problems, over a variety of compilers and systems.

More power to you. For us, we've had bad experiences doing this with
one particular third party library we have to use (customer
requirement, library is the industry standard). We make heavy use of
std::string, std::vector within modules, we just avoid making them
part of the exposed interface. It's a bit of a pain, but until the C++
standard defines an ABI all compilers must adhere to, we have little
choice. Unfortunately, my understanding is that this has been pushed
out beyond the next draft.
 
J

James Kanze

Fair enough.

But of course, we all count on a little bit more from time to
time:).
Um, I believe I said exactly the same compiler version and flags. If
you use the same settings on the same compiler for the same platform,
you should get the same byte order, padding, pointer size, etc.

If you use the same settings on the same compiler for the same
platform, you also have the same version of the standard
library.

Different compilers make different guarantees with regards to
"binary compatibility", but if binary compatability is
guaranteed between the different options, versions, etc., then
there should be no problem with the standard library either. If
it's not, on the other hand, you're likely to have problems with
POD struct's, pointers and---it happened once to me---even
longs or double. The standard library is part of the compiler,
and is covered by the sane "binary compatability" guarantees as
the rest.
Agreed. If you change a compiler option which causes a different
pointer size, you should expect things to explode. ;) I think the
main point is to know what compiler and flags were used to build the
shared library you want to use. It is then your responsibility to use
compatible flags for your own code.
Unless different modules have their own memory heap (we have
encountered situations where some do).

As far as I know, that never occurs under Unix, and only if you
don't take the proper precautions under Windows. (On the other
hand, I'm not sure who has to take the precautions: the user, or
the supplier of the DLL.) But that's a larger problem: you
can't free memory in one DLL that was allocated in another. Not
using components from the standard library isn't enough to avoid
problems.
Then you run the risk of having
memory allocated in one module and then when you resize the string,
vector, etc in another module the memory needs to be freed in that
module and BOOM! Even if memory is always allocated/deallocated from
the one heap, having std::string, std::vector or any other container
in the interface prevents you from doing some cool stuff like use an
alternate STL implementation in your own code (such as STLport for
improved error checking). But "cool stuff" is just that, not
necessarily "required stuff". ;)

I'm very sceptical about swapping the standard library. It's
part of the compiler, and you never know how much knowledge of
its implementation is built into the compiler.
More power to you. For us, we've had bad experiences doing this with
one particular third party library we have to use (customer
requirement, library is the industry standard). We make heavy use of
std::string, std::vector within modules, we just avoid making them
part of the exposed interface. It's a bit of a pain, but until the C++
standard defines an ABI all compilers must adhere to, we have little
choice. Unfortunately, my understanding is that this has been pushed
out beyond the next draft.

The C++ standard will never define an ABI, since this is, by its
very nature, platform specific.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,294
Messages
2,571,510
Members
48,195
Latest member
Tomjerry

Latest Threads

Top