C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Wierd Map Behavior

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
subaruwrx88011
Guest





PostPosted: Tue Feb 21, 2006 12:06 am    Post subject: Wierd Map Behavior Reply with quote



I am very new to c++ and very new to the idea of maps. Below is the
source of my program. I am getting wierd output from the print and I
actually think it might be inserting wrong. Can you guys help me.

#include <string>
#include <iostream>
#include <map>
#include <sstream>

class CCSI_Env
{

public:


int setItemState(std::string item, std::string state);

void print();

private:

struct StateStruct
{
std::string type;
union
{
int m_integer;
char* m_string;
float m_float;
} stateUnion;
};

//Map with string for the key and StateType for Value
typedef std::map<std::string, StateStruct> ItemStateMap;

//Item/State value pair of the enviroment
static ItemStateMap m_itemMap;

};

CCSI_Env::ItemStateMap CCSI_Env::m_itemMap = ItemStateMap();


int CCSI_Env::setItemState(std::string p_item, std::string p_state)
{
StateStruct itemState;

//Store state as union
itemState.type = "STRING";
itemState.stateUnion.m_string = (char*)p_state.c_str();//Convert to
char*

//Store item with state in map
m_itemMap[p_item] = itemState;


return 0;
}

void CCSI_Env::print()
{
ItemStateMap::iterator mapIterator;
std::string message;

std::cout<<"******"<<std::endl;

for(mapIterator = m_itemMap.begin(); mapIterator != m_itemMap.end();
mapIterator++)
{
if(mapIterator->second.type == "STRING")
{
message = mapIterator->first + " = " +
mapIterator->second.stateUnion.m_string;
std::cout << message << std::endl;
}

}

std::cout<<"******"<<std::endl;

}





int main()
{
CCSI_Env m_env;
int status;
std::string s,t;



s = "ONE";
t = "Online";
status = m_env.setItemState(s,t);

m_env.print();

s = "TWO";
t = "Online";
status = m_env.setItemState(s,t);

m_env.print();

s = "THREE";
t = "Offline";
status = m_env.setItemState(s,t);

m_env.print();

s = "FOUR";
t = "Offline";
status = m_env.setItemState(s,t);

m_env.print();
}

The output should be:
******
ONE = Online
******
******
ONE = Online
TWO = Online
******
******
ONE = Online
THREE = Offline
TWO = Online
******
******
FOUR = Offline
ONE = Online
THREE = Offline
TWO = Online
******


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Tue Feb 21, 2006 11:06 am    Post subject: Re: Wierd Map Behavior Reply with quote



subaruwrx88011 wrote:
Quote:
I am very new to c++ and very new to the idea of maps. Below
is the source of my program. I am getting wierd output from
the print and I actually think it might be inserting wrong.
Can you guys help me.

#include <string
#include <iostream
#include <map
#include <sstream

class CCSI_Env
{
public:
int setItemState(std::string item, std::string state);
void print();

private:
struct StateStruct
{
std::string type;
union
{
int m_integer;
char* m_string;
float m_float;
} stateUnion;
};

//Map with string for the key and StateType for Value
typedef std::map<std::string, StateStruct> ItemStateMap;

//Item/State value pair of the enviroment
static ItemStateMap m_itemMap;
};

CCSI_Env::ItemStateMap CCSI_Env::m_itemMap = ItemStateMap();

You don't need the = ... here. An std::map has a non-trivial
constructor, which will be called during program start up.

Quote:
int CCSI_Env::setItemState(std::string p_item, std::string p_state)
{
StateStruct itemState;

//Store state as union
itemState.type = "STRING";
itemState.stateUnion.m_string = (char*)p_state.c_str();//Convert to
char*

Be very careful here. string::c_str() returns a pointer to
internal data, which is only guaranteed to be valid until the
next non-const function which is called on the string.

In general, in StateStruct, you should probably use std::string,
and not char*. I would use char const* if all of the strings
were known to actually be literals, or for order of
initialization issues (not an issue here), but that's about it.
And I can't think of any case where I would use char* in a
class; if I'm going to modify the string, I definitly want to
use std::string, so as not to have to manage the memory myself.

Of course, this means that you cannot use a union, but big deal.
Using a struct here won't kill you.

Quote:
//Store item with state in map
m_itemMap[p_item] = itemState;

return 0;

After this statement, the pointer returned by p_state.c_str() is
invalid. Since you left a copy of it in the map, your program
now has undefined behavior. Anything may happen.
Quote:
}

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Daniel T.
Guest





PostPosted: Tue Feb 21, 2006 11:06 am    Post subject: Re: Wierd Map Behavior Reply with quote



In article <1140465890.840553.265600 (AT) f14g2000cwb (DOT) googlegroups.com>,
"subaruwrx88011" <subaruwrx88011 (AT) gmail (DOT) com> wrote:

Quote:
I am very new to c++ and very new to the idea of maps. Below is the
source of my program. I am getting wierd output from the print and I
actually think it might be inserting wrong. Can you guys help me.

int CCSI_Env::setItemState(std::string p_item, std::string p_state)
{
StateStruct itemState;

//Store state as union
itemState.type = "STRING";
itemState.stateUnion.m_string = (char*)p_state.c_str();/*Convert to
char* */

//Store item with state in map
m_itemMap[p_item] = itemState;

return 0;
}

The function above will not work. You store the result of
string::c_str() in a char*, but its lifetime is not guaranteed. What you
need to do is copy the result of the c_str into memory that you manage.

Personally, I would dump the whole idea of a union. Store the data as a
string, if you need to convert to an integer or float, do it on the fly.

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Schüle Daniel
Guest





PostPosted: Tue Feb 21, 2006 11:06 am    Post subject: Re: Wierd Map Behavior Reply with quote

subaruwrx88011 wrote:

Quote:
#include <string
#include <iostream
#include <map
#include <sstream

class CCSI_Env
{

public:


int setItemState(std::string item, std::string state);

better
int setItemState(std::string const & item, std::string const & state);
think why Smile
notice const &

Quote:

void print();

private:

struct StateStruct
{
std::string type;
union
{
int m_integer;
char* m_string;
float m_float;
} stateUnion;
};

//Map with string for the key and StateType for Value
typedef std::map<std::string, StateStruct> ItemStateMap;

//Item/State value pair of the enviroment
static ItemStateMap m_itemMap;

};

CCSI_Env::ItemStateMap CCSI_Env::m_itemMap = ItemStateMap();

CCSI_Env::ItemStateMap CCSI_Env::m_itemMap;

is sufficient

Quote:


int CCSI_Env::setItemState(std::string p_item, std::string p_state)
{
StateStruct itemState;

//Store state as union
itemState.type = "STRING";
itemState.stateUnion.m_string = (char*)p_state.c_str();//Convert to
char*

bad idea
do you have the guarantie that string, when it gets bigger and bigger
won't reallocate itself to some other memory location?
leaving you with wild pointer pointing to nirvana

Regards, Daniel


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Andrea Griffini
Guest





PostPosted: Tue Feb 21, 2006 11:06 am    Post subject: Re: Wierd Map Behavior Reply with quote

Quote:
int CCSI_Env::setItemState(std::string p_item, std::string p_state)
{
StateStruct itemState;
//Store state as union
itemState.type = "STRING";
itemState.stateUnion.m_string =
(char*)p_state.c_str();//Convert to char*
//Store item with state in map
m_itemMap[p_item] = itemState;
return 0;
}

This function has a problem with lifetimes. When you call "c_str()" the
returned value is a pointer to the first char of a NUL-terminated
C-string but, and this is a most important point, you do not OWN the
returned string. In the specific the returned string is a property of
the object instance you're asking it to, namely p_state.
What happens in the code is that you're taking this pointer to char and
storing it in the map where then pointer will live longer than the
pointed to sequence of characters; when the function exits the
parameter p_state will be destroyed and after that time you're no more
allowed to look to what c_str() returned.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kupoo
Guest





PostPosted: Thu Mar 09, 2006 11:06 am    Post subject: Re: Wierd Map Behavior Reply with quote

subaruwrx88011 wrote:
Quote:
I am very new to c++ and very new to the idea of maps. Below is the
source of my program. I am getting wierd output from the print and I
actually think it might be inserting wrong. Can you guys help me.
Use question marks. You say you are new to maps, and it's "inserting

wrong" which leads me to think you think maps are ordered. It's a
common mistake for people new to maps, so disregard this if you already
know about it. When you relate two types say for instance:
---
A a;
B b;
map<A,B> r;
r[a] = b;
---
You are not setting the order of the map's keys. That is done behind
the scenes, and is not really predictable. The standard C++ says you
should never depend on the order of a map's keys. Thus when you go from
map.begin() to map.end(), you can't tell which key will come up first.
You didn't provide a copy of the actual weird output, but I imagine it
is something like this:
---
******
ONE = Online
******
******
ONE = Online
TWO = Online
******
******
THREE = Offline
ONE = Online
TWO = Online
******
******
TWO = Online
FOUR = Offline
ONE = Online
THREE = Offline
******
---
....with an order to the keys different from the order in which you added
them. There may be an auxiliary std:: type that functions as an ordered
map, but what I usually do when the keys need to stay in order is: pair
together a map, and a std::queue or std::stack (depending on FIFO or
LIFO). Upon adding a key,value pair to the map, I add a new entry to
its corresponding key vector! Clumsy, but it can be encapsulated, and
thankfully for most all applications of maps we do not need the keys to
stay in a certain order.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Fri Mar 10, 2006 2:06 pm    Post subject: Re: Wierd Map Behavior Reply with quote

kupoo wrote:
Quote:
subaruwrx88011 wrote:

I am very new to c++ and very new to the idea of maps. Below
is the source of my program. I am getting wierd output from
the print and I actually think it might be inserting wrong.
Can you guys help me.

Use question marks. You say you are new to maps, and it's
"inserting wrong" which leads me to think you think maps are
ordered.

If he's using std::map, it is ordered. In TR1, I think, there
is an unordered_map, but the standard map is ordered.

Quote:
It's a common mistake for people new to maps, so disregard
this if you already know about it. When you relate two types
say for instance:

---
A a;
B b;
map<A,B> r;
r[a] = b;
---

You are not setting the order of the map's keys.

The order of the map's keys is defined by the ordering
relationship of the map -- std::less, by default, but the user
can specify what he wants.

Quote:
That is done behind the scenes, and is not really predictable.
The standard C++ says you should never depend on the order of
a map's keys.

Where did you learn this? It is very definitly wrong; the order
is strictly defined.

Quote:
Thus when you go from map.begin() to map.end(), you can't tell
which key will come up first.

You must definitly can.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.