One more reason for using std::string instead of char * in C++ programs.

N

Neil Zanella

Hello,

Consider the following program. There are two C style string stack variables
and one C style string heap variable. The compiler may or may not optimize
the space taken up by the two stack variables by placing them at the same
address (my g++ compiler does this). Therefore the output of the given
C program is compiler dependent. What is worse, the program does not
do what its writer most likely intended, since, std::set's find()
method uses an implicit == operator for comparison, which in this
case does an address comparison (no way to do an strcmp in this
case seems possible). So the problem is simply solved by using
the string class which was in the mind of the designers of C++
when the STL was created, namely, std::string.

Regards,

Neil


---------------- code follows -------------------------------------------

#include <iostream>
#include <cstdlib>
#include <set>

int main() {
std::set<char *> foo;
foo.insert("hello");

char *bar1 = "hello", *bar2;
if ((bar2 = (char *) malloc(6)) == 0) {
std::cout << "not enough memory" << std::endl;
exit(EXIT_FAILURE);
}

if (foo.find(bar1) != foo.end())
std::cout << "hello" << std::endl;
else
std::cout << "good night" << std::endl;

if (foo.find(bar2) != foo.end())
std::cout << "hello" << std::endl;
else
std::cout << "good night" << std::endl;

}
 
D

David Hilsee

Neil Zanella said:
Hello,

Consider the following program. There are two C style string stack variables
and one C style string heap variable. The compiler may or may not optimize
the space taken up by the two stack variables by placing them at the same
address (my g++ compiler does this). Therefore the output of the given
C program is compiler dependent. What is worse, the program does not
do what its writer most likely intended, since, std::set's find()
method uses an implicit == operator for comparison, which in this
case does an address comparison (no way to do an strcmp in this
case seems possible). So the problem is simply solved by using
the string class which was in the mind of the designers of C++
when the STL was created, namely, std::string.
[snipped code that uses std::set<char*>]

Also, allocating the character arrays can be a pain because it can lead to
an off-by-one error for the null terminator, and you are forced to manually
deallocate any c-style strings that you dynamically allocated for the
std::set. There are many reasons why C-style strings are a pain when
compared to std::string.

Nitpick: std::set<char *> uses the std::less<char *> comparison (a default
template parameter) to determine equality. The unexpected behavior's pretty
much the same, though. This behavior could be eliminated by providing a
comparison functor template parameter that "understands" c-style strings
(e.g. std::set<char *, CStringLessThan>).
 
J

John Harrison

Hello,

Consider the following program. There are two C style string stack
variables
and one C style string heap variable. The compiler may or may not
optimize
the space taken up by the two stack variables by placing them at the same
address (my g++ compiler does this).

It seems unlikely since both variables are in use at the same time.
Therefore the output of the given
C program is compiler dependent.

This is incorrect, you seem to be confusing the address of the variable
itself, with the address that each variable hold (each variable being a
pointer). Its the address that the variable holds that is used to search
in the set.

However the output is compiler dependent, but it depends on whether the
two string literals "hello" have the same address, and I believe that is
compiler dependent.
What is worse, the program does not
do what its writer most likely intended, since, std::set's find()
method uses an implicit == operator for comparison, which in this
case does an address comparison

That I can't disagree with.
(no way to do an strcmp in this
case seems possible).

It's possible by supplying a custom comparision object.

struct StrCmp : public std::binary_function<char*, char*, bool>
{
bool operator()(char* x, char* y)
{
return strcmp(x, y) < 0;
}
};

std::set said:
So the problem is simply solved by using
the string class which was in the mind of the designers of C++
when the STL was created, namely, std::string.

Can't disagree that, using a std::string as the key is normally what you
should do.
Regards,

Neil

john
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top