Broken STL implementation? | | |
Is my implementation correct to print only a blank line when the
following program is compiled and run?
#include <iostream>
#include <map>
int main()
{
std::map< const char *, std::string > m;
m["foo"]="bar";
std::cout << m["foo"] << std::endl;
return 0;
}
g++ prints "bar", which is of course the behavior I want. If this is
a(nother) problem with my implementation, what, if anything, can I do
to work around it?
--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome. | | | | re: Broken STL implementation?
Christopher Benson-Manica wrote:[color=blue]
> Is my implementation correct to print only a blank line when the
> following program is compiled and run?
>
> #include <iostream>
> #include <map>
>
> int main()
> {
> std::map< const char *, std::string > m;
> m["foo"]="bar";
> std::cout << m["foo"] << std::endl;
> return 0;
> }
>
> g++ prints "bar", which is of course the behavior I want. If this is
> a(nother) problem with my implementation, what, if anything, can I do
> to work around it?[/color]
There is no guarantee that the first "foo" and the second "foo" are
the same constant string. Both implementations are, therefore, correct.
The work-around is to ensure that you're passing the same pointer value
both times:
int main()
{
..
const char *pfoo = "foo";
m[pfoo] = "bar";
std::cout << m[pfoo] << std::endl;
}
Victor | | | | re: Broken STL implementation?
On Wed, 18 Aug 2004 16:09:02 +0000 (UTC), Christopher Benson-Manica
<ataru@nospam.cyberspace.org> wrote:
[color=blue]
>Is my implementation correct to print only a blank line when the
>following program is compiled and run?
>
>#include <iostream>
>#include <map>
>
>int main()
>{
> std::map< const char *, std::string > m;[/color]
Ok, so your map is flawed already - you can't < compare pointer values
unless those pointers point into the same object (or array).
[color=blue]
> m["foo"]="bar";
> std::cout << m["foo"] << std::endl;[/color]
The second "foo" may or may not have the same address as the first one
- it's unspecified. So that may or may not have undefined behaviour
(which is what you're seeing).
[color=blue]
> return 0;
>}
>
>g++ prints "bar", which is of course the behavior I want. If this is
>a(nother) problem with my implementation, what, if anything, can I do
>to work around it?[/color]
I think you way to have the map sorted according to the contents of
the string, not the pointer value? If so, then you need something
like:
#include <cstring>
struct strcmper
{
typedef bool result_type;
typedef const char* first_argument_type;
typedef const char* second_argument_type;
bool operator()(const char* lhs, const char* rhs) const
{
return std::strcmp(lhs, rhs) < 0;
}
};
//...
std::map< const char *, std::string, strcmper > m;
Tom | | | | re: Broken STL implementation?
Christopher Benson-Manica wrote:
[color=blue]
> Is my implementation correct to print only a blank line when the
> following program is compiled and run?
>
> #include <iostream>
> #include <map>
>
> int main()
> {
> std::map< const char *, std::string > m;
> m["foo"]="bar";
> std::cout << m["foo"] << std::endl;
> return 0;
> }
>
> g++ prints "bar", which is of course the behavior I want. If this is
> a(nother) problem with my implementation, what, if anything, can I do
> to work around it?
>[/color]
This is not a problem with your library. The following code will yield a
blank line with g++, and I venture to say, on any standard complient
compiler:
#include <iostream>
#include <map>
int main()
{
char foo1 [4] = "foo";
char foo2 [4] = "foo";
std::map< const char *, std::string, std::less< const char * > m;
m[foo1]="bar";
std::cout << m[foo2] << std::endl;
return 0;
}
Back to your code:
[color=blue]
> std::map< const char *, std::string > m;[/color]
This is a bas idea: map operations will call operator< which is supposed to
be a weak total ordering. The standard makes no requirement that this holds
for comparision of const char *. Thus
std::map< const char *, std::string, std::less< const char * > m;
is better. However, it is clearly not what you want.
What happens is that your map m just stores a pointer to char and not a
copy of that string. Moreover, you donot compare the entries by their
values as strings but just by their address. Since foo1 and foo2 point to
different memory locations, the second programm prints a blank line. That
g++ prints "bar" for your code indicates that g++ folded the two occurences
of "foo" in your code to the same memory location: this tells us a little
bit about g++ handles string constants.
Recommendation: fix your code by using std::string for the keys in the map,
as well.
Best
Kai-Uwe | | | | re: Broken STL implementation?
Christopher Benson-Manica <ataru@nospam.cyberspace.org> wrote in
news:cfvuuu$fp4$1@chessie.cirr.com:
[color=blue]
> Is my implementation correct to print only a blank line when the
> following program is compiled and run?[/color]
Yes.
[color=blue]
> #include <iostream>
> #include <map>
>
> int main()
> {
> std::map< const char *, std::string > m;[/color]
Keep in mind that this means that std::map is using std::less<const char
*> to determine equivalence. So the map will be comparing pointer
values, not what they're pointing _at_....
[color=blue]
> m["foo"]="bar";[/color]
This string literal "foo" lives at some memory location somewhere. Say,
0x00000004. So you're effectively doing:
m[reinterpret_cast<const char *>(0x00000004)] = "bar";
[color=blue]
> std::cout << m["foo"] << std::endl;[/color]
This string literal "foo" _may_ live at a different memory location.
Say, 0x00000008. So you're effectively doing:
m[reinterpret_cast<const char *>(0x00000008)] = "bar";
A different index than the first one....
[color=blue]
> return 0;
> }
>
> g++ prints "bar", which is of course the behavior I want. If this is
> a(nother) problem with my implementation, what, if anything, can I do
> to work around it?[/color]
Make your map: std::map<std::string, std::string>. A second alternative
is to supply your own comparison functor that knows to follow the pointer
to the actual string and compare those.
g++ is probably doing a string folding optimization where the compiler
notices that "foo" and "foo" are the same string literal, thus can share
the same memory location. | | | | re: Broken STL implementation?
tom_usenet wrote in news:kc17i09r18pj5nkk2l2akdcg9l45qc9kd4@4ax.com in
comp.lang.c++:
[color=blue]
>
> Ok, so your map is flawed already - you can't < compare pointer values
> unless those pointers point into the same object (or array).
>
>[/color]
No, the map uses std::less< char const * > which is required to
handle such cases 20.3.3/8.
Rob.
-- http://www.victim-prime.dsl.pipex.com/ | | | | re: Broken STL implementation?
"Kai-Uwe Bux" <jkherciueh@gmx.net> wrote in message
news:cg016b$mqc$1@news01.cit.cornell.edu...
<snip>[color=blue][color=green]
> > std::map< const char *, std::string > m;[/color]
>
> This is a bas idea: map operations will call operator< which is supposed[/color]
to[color=blue]
> be a weak total ordering. The standard makes no requirement that this[/color]
holds[color=blue]
> for comparision of const char *. Thus
>
> std::map< const char *, std::string, std::less< const char * > m;
>
> is better. However, it is clearly not what you want.[/color]
<snip>
FYI, std::map's third template argument defaults to std::less<Key>. Your
"correction" is equivalent to the original code.
--
David Hilsee | | | | re: Broken STL implementation?
David Hilsee wrote:
[color=blue]
> "Kai-Uwe Bux" <jkherciueh@gmx.net> wrote in message
> news:cg016b$mqc$1@news01.cit.cornell.edu...
> <snip>[color=green][color=darkred]
>> > std::map< const char *, std::string > m;[/color]
>>
>> This is a bas idea: map operations will call operator< which is supposed[/color]
> to[color=green]
>> be a weak total ordering. The standard makes no requirement that this[/color]
> holds[color=green]
>> for comparision of const char *. Thus
>>
>> std::map< const char *, std::string, std::less< const char * > m;
>>
>> is better. However, it is clearly not what you want.[/color]
> <snip>
>
> FYI, std::map's third template argument defaults to std::less<Key>. Your
> "correction" is equivalent to the original code.
>[/color]
Thanks!
Kai-Uwe Bux | | | | re: Broken STL implementation?
On 18 Aug 2004 21:11:57 GMT, Rob Williscroft <rtw@freenet.co.uk>
wrote:
[color=blue]
>tom_usenet wrote in news:kc17i09r18pj5nkk2l2akdcg9l45qc9kd4@4ax.com in
>comp.lang.c++:
>[color=green]
>>
>> Ok, so your map is flawed already - you can't < compare pointer values
>> unless those pointers point into the same object (or array).
>>
>>[/color]
>
>No, the map uses std::less< char const * > which is required to
>handle such cases 20.3.3/8.[/color]
Interesting, I didn't realise that std::less ever did anything beyond
<.
Tom | | | | re: Broken STL implementation?
Christopher Benson-Manica wrote:[color=blue]
> Is my implementation correct to print only a blank line when the
> following program is compiled and run?
>
> #include <iostream>
> #include <map>
>
> int main()
> {
> std::map< const char *, std::string > m;
> m["foo"]="bar";
> std::cout << m["foo"] << std::endl;
> return 0;
> }
>
> g++ prints "bar", which is of course the behavior I want. If this is
> a(nother) problem with my implementation, what, if anything, can I do
> to work around it?[/color]
The above is not a well-defined behaviour.Use map<string, string> instead.
The two string literals used, may have different addresses.
Regards,
Ioannis Vranos http://www23.brinkster.com/noicys |  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,449 network members.
|