 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
subaruwrx88011 Guest
|
Posted: Tue Feb 21, 2006 12:06 am Post subject: Wierd Map Behavior |
|
|
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
|
Posted: Tue Feb 21, 2006 11:06 am Post subject: Re: Wierd Map Behavior |
|
|
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.
--
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
|
Posted: Tue Feb 21, 2006 11:06 am Post subject: Re: Wierd Map Behavior |
|
|
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
|
Posted: Tue Feb 21, 2006 11:06 am Post subject: Re: Wierd Map Behavior |
|
|
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
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
|
Posted: Tue Feb 21, 2006 11:06 am Post subject: Re: Wierd Map Behavior |
|
|
| 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
|
Posted: Thu Mar 09, 2006 11:06 am Post subject: Re: Wierd Map Behavior |
|
|
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
|
Posted: Fri Mar 10, 2006 2:06 pm Post subject: Re: Wierd Map Behavior |
|
|
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 |
|
 |
|
|
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
|
|