• Advertisement
Sign in to follow this  

Pointer Type STL Map, How can I Iterate?

This topic is 4308 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

//Skin.h
	std::map<std::string, std::string>* skinData;

//Skin.cpp
Skin::Skin{
	skinData=NULL; 
}

void Skin::Read( std::string para_loadKey, std::map<std::string, std::string>& para_skinData ){
	skinData=&para_skinData; 
	Read( para_loadKey);
}

//The below is a segmentation Error
std::cout << (*skinData)["subject"];


Segmentation Error Descriptions: Program received signal SIGSEGV, Segmentation fault. 0x0804faee in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_begin (this=0x0) at stl_tree.h:462 462 { return static_cast<_Link_type>(this->_M_impl._M_header._M_parent); } (gdb) bt #0 0x0804faee in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::_M_begin (this=0x0) at stl_tree.h:462 #1 0x080505c5 in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::lower_bound (this=0x0, __k=@0xbfbfe270) at stl_tree.h:1146 #2 0x08050665 in std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::lower_bound ( this=0x0, __x=@0xbfbfe270) at stl_map.h:540 #3 0x08051aed in std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::operator[] ( this=0x0, __k=@0xbfbfe270) at stl_map.h:336 #4 0x08063f4d in Skin::ParseFunctions (this=0xbfbfe3f0, para_skinTypeValue=@0xbfbfe2c0) at Skin.cpp:210 #5 0x08064833 in Skin::Read (this=0xbfbfe3f0, para_loadKey=@0xbfbfeb68) at Skin.cpp:175 #6 0x0804ee8a in main (argc=2, argv=0xbfbfec30) at new_shenu.cpp:139 Please,

Share this post


Link to post
Share on other sites
Advertisement

std::map<std::string,std::string>::pointer ploop;

for( ploop=skinData->begin(); ploop!=skinData->end(); ploop++ ){
std::cout << loop->first << "=" << loop->second << "\n";
}



I want to run this too.
compiles fine.
Segmentation Error.
What's going on?

Share this post


Link to post
Share on other sites
You don't provide nearly enough information to know for sure, but it sounds to me as though you've got a map that hasn't been created yet. Or, given the form of your read function, it was created and then destroyed before you used your pointer.

CM

Share this post


Link to post
Share on other sites

mainConfig.SetConfig( "./system/db/" + mainParameter.GetParameterValue("db") + "/config.cgi" );

std::map<std::string, std::string> nextDbf;
algorithms::Instance().ParseData( nextDbf, "./system/db/" + mainParameter.GetParameterValue("db") + "/data.cgi" );

if ( mainConfig.GetConfigValue("SnPageLine") == "" )
mainConfig.SetConfig("SnPageLine","1");

int countData=0;
std::string tempifstream;
for( int i=(int)algorithms::Instance().ToInt( nextDbf["dbf"] )-1; i > 0; i-- ){
tempifstream="./system/db/" + mainParameter.GetParameterValue("db") + "/data/" + algorithms::Instance().ToString(i) + ".cgi";
if( ifstream( tempifstream.c_str() ) ){
mainData.SetData( algorithms::Instance().ToString(i), "./system/db/" + mainParameter.GetParameterValue("db") + "/data/" + algorithms::Instance().ToString(i) + ".cgi" );
countData++;
}
if ( countData == (int)algorithms::Instance().ToInt(mainConfig.GetConfigValue("SnPageLine")) )
break;
}

std::map< std::string, std::map< std::string, std::string > >::iterator mainlooparray[countData];
int countDataTrack=0;
for( std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=mainData.GetData().begin(); mainloop != mainData.GetData().end(); ++mainloop ){
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}



std::map< std::string, std::map< std::string, std::string > >::iterator mainloop;
std::map< std::string, std::string >::iterator mainloop2;
print::Instance().Header( "success4" );
Skin skin("system/skins/list.shenu", mainCookie, mainParameter, mainPath, mainConfig );

print::Instance().Body( "" );
skin.Read("Head");

for ( int i=0; i<countData; i++ ){
mainloop=mainlooparray[i];

for ( mainloop2=mainloop->second.begin(); mainloop2!=mainloop->second.end(); ++mainloop ){
std::cout << mainloop2->first << "=" << mainloop2->second;
}

//skin.Read("Body", mainloop->second );
}

skin.Read("Tail");
print::Instance().Tail( "" );


This is my main.

please help me.

Share this post


Link to post
Share on other sites
The first thing that comes to mind is this line:

for ( mainloop2=mainloop->second.begin(); mainloop2!=mainloop->second.end(); ++mainloop ){

I suspect you meant to increment mainloop2. That should have lead to an infinite loop, but you probably got [un]lucky in that once mainloop went out of bounds, it triggered mainloop2==mainloop->second.end() You then exit the loop, but mainloop is still out of bounds, so your read function fails.

CM

Share this post


Link to post
Share on other sites
I really seriously can't find the syntax for incrementing mainloop2,
can you please tell me?

Share this post


Link to post
Share on other sites
The syntax for incrementing mainloop2 would be ++mainloop2, i.e.:
for ( mainloop2=mainloop->second.begin();
mainloop2!=mainloop->second.end();
++mainloop2 ){
std::cout << mainloop2->first << "=" << mainloop2->second;
}

Question: What is the return type of the member function mainData.GetData()? If it returns by value then this loop:
for( std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=mainData.GetData().begin(); mainloop != mainData.GetData().end(); ++mainloop ){
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}

will be comparing iterators into different copies of the same map, which is undefined behaviour. It's a bit like if you did:
std::map< std::string, std::map< std::string, std::string > > temp1 = mainData.GetData();
std::map< std::string, std::map< std::string, std::string > > temp2 = mainData.GetData();
for (std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=temp1.begin(); mainloop != temp2.end(); ++mainloop)
{
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}

If mainData.GetData() returns by reference then you're OK (on that point).

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Tradone
I really seriously can't find the syntax for incrementing mainloop2,
can you please tell me?

It works just like incrementing mainloop: ++mainloop2.

CM

Share this post


Link to post
Share on other sites
std::map< std::string, std::map< std::string, std::string > > GetData(){
return data;
};


it returns std::map< std::string, std::map< std::string, std::string > >

Share this post


Link to post
Share on other sites
Quote:
Original post by Conner McCloud
Quote:
Original post by Tradone
I really seriously can't find the syntax for incrementing mainloop2,
can you please tell me?

It works just like incrementing mainloop: ++mainloop2.

CM


yea that was a really dumb mistake,
that's what i get for writing confusing names, but I just wanted it mainloop2 temporarily to test if I can call the map ( mainloop2->second )

Share this post


Link to post
Share on other sites
I'm really lost

So this is not logical?
It seems logical to me

std::map< std::string, std::map< std::string, std::string > > temp1 = mainData.GetData();
std::map< std::string, std::map< std::string, std::string > > temp2 = mainData.GetData();
for (std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=temp1.begin(); mainloop != temp2.end(); ++mainloop)
{
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}

Share this post


Link to post
Share on other sites
so I should make them return by reference.
if you look at the link I provided above, you will see why I had to use an array of pointers.

okay, so I'll change the type.

now since GetData is returning the address of :
&map< string, map>
then I need to change


for( std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=mainData.GetData().begin(); mainloop != mainData.GetData().end(); ++mainloop ){
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}



wouldn't I have to change the iterator type? to be iterator* mainloop=mainData.GetData().begin(); ????

Share this post


Link to post
Share on other sites
Sorry Run_The_Shadows, but that is incorrect. for (iterator i = container.begin(); i != container.end(); ++i) is semantically identical to for (iterator i = container.begin(); i != container.end(); i++) and potentially more efficient. The only issue would be if you were to access the value returned from the increment operator, then pre-increment would have the potential to cause a one-past-the-end error.

Tradone: In my earlier example temp1 and temp2 are entirely separate maps which just happen to contain the same contents. An iterator into one will never point to the end of the other. Consider, for example:
std::map< std::string, std::map< std::string, std::string > > temp1 = mainData.GetData();
std::map< std::string, std::map< std::string, std::string > > temp2 = mainData.GetData();
temp2.insert(/* something */);
for (std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=temp1.begin(); mainloop != temp2.end(); ++mainloop)
{
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}

What would you expect that to do?

As to the second point - if you return by pointer (*) then you will need to dereference the returned value (iterator* mainloop=(*mainData.GetData()).begin(); or iterator* mainloop=mainData.GetData()->begin();). If you return by reference (&) then no dereference is required.

Σnigma

Share this post


Link to post
Share on other sites
For the love of Pete, use typedefs!


typedef std::map< std::string, std::string > string_map;
typedef std::map< std::string, string_map > string_map_map;


Next, use some aliases:


string_map_map& map_in_use = mainData.GetData();


There is no reason why your code has to be this "read only".

Next question: what is the type that mainData.GetData() returns?

I hope it isn't returning a copy of your map.

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
What would you expect that to do?

I expect that to give me the same results as this snippet:

std::map< std::string, std::map< std::string, std::string > > temp = mainData.GetData();
temp.insert< somestring, somemap >

for (std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=temp.begin(); mainloop != temp.end(); ++mainloop)
{
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}




Quote:
Original post by Enigma
As to the second point - if you return by pointer (*) then you will need to dereference the returned value (iterator* mainloop=(*mainData.GetData()).begin(); or iterator* mainloop=mainData.GetData()->begin();). If you return by reference (&) then no dereference is required.



//some header file
//so i made it return a reference
std::map< std::string, std::map< std::string, std::string > >& GetData(){
return data;
};


//main.cpp
std::map< std::string, std::map< std::string, std::string > >::iterator mainlooparray[countData];
int countDataTrack=0;
for( std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=mainData.GetData().begin(); mainloop != mainData.GetData().end(); ++mainloop ){
//now it stores the address of the memory location of my maps.
mainlooparray[countDataTrack]=mainloop;
countDataTrack++;
}


for ( int i=0; i<countData; i++ ){
mainloop=mainlooparray[i];
//yet still fails to open. with a segmentation error.
for ( mainloop2=mainloop->second.begin(); mainloop2!=mainloop->second.end(); ++mainloop2 ){
std::cout << mainloop2->first << "=" << mainloop2->second;
}

//skin.Read("Body", mainloop->second );
}











Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
Sorry Run_The_Shadows, but that is incorrect. for (iterator i = container.begin(); i != container.end(); ++i) is semantically identical to for (iterator i = container.begin(); i != container.end(); i++) and potentially more efficient. The only issue would be if you were to access the value returned from the increment operator, then pre-increment would have the potential to cause a one-past-the-end error.


Ugh. You're right and I can't quite figure the specifics of why. I know that I've had ++iter issues about 3 times in the past month that always caused crashes and now, writing up a quickie test app, I can't reproduce them. Consider me mocked and your rating increased. Nice call!

Share this post


Link to post
Share on other sites
Quote:
Original post by NotAYakk
For the love of Pete, use typedefs!


typedef std::map< std::string, std::string > string_map;
typedef std::map< std::string, string_map > string_map_map;


Next, use some aliases:


string_map_map& map_in_use = mainData.GetData();


There is no reason why your code has to be this "read only".

Next question: what is the type that mainData.GetData() returns?

I hope it isn't returning a copy of your map.


it's returning a copy of my map,
but i changed it so that it returns a reference but still no luck i am getting the same segmentation errors.

Share this post


Link to post
Share on other sites
My HP (ratings) is steadingly failing me, can't you see that i'm dying here?

Share this post


Link to post
Share on other sites
You are probably copying the map somewhere.

Copying the map will cause problems -- it is expensive, and it is probably causing your seg faults.

Stop using std::map. Write the following:

template<typename T, typename U>
struct map_nocopy {
typedef map_nocopy<T,U> my_type;
typedef std::map<T,U> map_type;
typedef map_type::iterator iterator;
typedef map_type::const_iterator const_iterator;
typedef std::pair<T,U> value_type;

private:
map_type data;
public:
map_type& value() {return data;};
map_type const& value() const {return data;};

map_type& operator->() { return value(); };
map_type const& operator->() const { return value(); };

U& operator[](int n) {return data[n];}
private:
void operator=(const my_type&); // NO IMPLEMENTATION
map_nocopy (const my_type&); // NO IMPLEMENTATION
public:
map_nocopy (const map_type&m):data(m){}
void swap (map_type&m) {std::swap(data, m){}
map_nocopy const& operator=(const map_type&m){my_type tmp=m;swap(tmp);return *this;};
};


Avoid calling "value()" as much as possible.

The above class will act like a map -- operator[] will work like a map, but to access begin() and end() you need to use "->" instead of ".".

If changing to map_nocopy doesn't help, then add in printf's to the constructor/destructor of map_nocopy and see if you are still creating/destroying maps accidentally.

(PS: the above code was written by hand and I haven't compiled it. Odds are there is a syntax error in it. Run it in a toy file before testing it in an entire project.)

Share this post


Link to post
Share on other sites

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


class Data{
public:
Data();

void SetData();
std::map< std::string, std::map< std::string, std::string > >& GetData(){
return data;
};
std::map< std::string, std::string > GetData(std::string key){
return data[key];
};

//end public:

private:
std::map< std::string, std::map< std::string, std::string > > data;
int countKey;
//end private:
};

Data::Data(){
countKey=0;
}

void Data::SetData(){
std::map <std::string, std::string> tempdata;
tempdata.insert(std::pair<std::string, std::string >( "1" , "one" ));
tempdata.insert(std::pair<std::string, std::string >( "2" , "two" ));
tempdata.insert(std::pair<std::string, std::string >( "3" , "three" ));
tempdata.insert(std::pair<std::string, std::string >( "4" , "four" ));

std::string key;
if ( countKey == 0 )
key="USA";
if ( countKey == 1 )
key="UK";
if ( countKey == 2 )
key="JAPAN";
if ( countKey == 3 )
key="GERMANY";
if ( countKey == 4 )
key="RUSSIA";
if ( countKey == 5 )
key="INDIA";

data.insert(std::pair<std::string, std::map<std::string, std::string> >( key , tempdata ));
countKey++;
}

int main( int argc, char* argv[] ){
//make an object Data.
//Data objects store map<string,map> type of data.
Data mainData;

int countData=0;

//make 4 Set Datas.
//meaning, make up to RUSSIA.
for( int i=5; i > 0; i-- ){
mainData.SetData( );
countData++;
}

//countData should be 4, so dynamically create an array of iterators that can hold 4 iterators.
std::map< std::string, std::map< std::string, std::string > >::iterator mainlooparray[countData];

//reuse countData to assign the correct array# to mainlooparray.
countData=0;
for( std::map< std::string, std::map< std::string, std::string > >::iterator mainloop=mainData.GetData().begin(); mainloop != mainData.GetData().end(); ++mainloop ){
mainlooparray[countData]=mainloop;
countData++;
}
//again, countData should be 4
//more over mainlooparray should be an iterator of specific positions of data.

//mainloop is declared, and mainloop's main purpose is to hold what is inside mainlooparray[specific_iterator]
std::map< std::string, std::map< std::string, std::string > >::iterator mainloop;
//mainloop2's job is to iterate a map.
std::map< std::string, std::string >::iterator mainloop2;

//error is caused here.
for ( int i=0; i<countData; i++ ){
mainloop=mainlooparray[i];
for ( mainloop2=mainloop->second.begin(); mainloop2!=mainloop->second.end(); ++mainloop2 ){
std::cout << mainloop2->first << "=" << mainloop2->second;
}
}



return 0;
}











gdb errors:
#0 0x0804a82c in std::_Rb_tree<std::string, std::pair<std::string const, std::string>, std::_Select1st<std::pair<std::string const, std::string> >, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::begin ()
#1 0x08049fb5 in std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >::begin ()
#2 0x08049838 in main ()






The above is a compilable code of the problem.
I can not communicate with words to fix this problem, if somebody can demonstrate me with code, that will be very helpful. I'm NOT trying to make you guys work for me, it took me 30 minutes just to make the code to a bare minimum where it still produces errors.

Thanks.

Share this post


Link to post
Share on other sites
The problem in the above code is that you're looping from 0 to 10 (the value of countData), and there is only 7 elements in the map. You probably want to count from 0 to 7 (the value of countDataTrack).

Share this post


Link to post
Share on other sites
Quote:
Original post by NotAYakk
You are probably copying the map somewhere.

Copying the map will cause problems -- it is expensive, and it is probably causing your seg faults.


Why would copying maps cause problems?
and how do you know this?
I'm not too familiar with templates so i'm going to look up on templates first before I use the code skippet you have provided me.

Thank you.

Share this post


Link to post
Share on other sites
Tried to rewrite your sample program.

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

class Data
{
public:
typedef std::map<std::string, std::string> InnerMap;
typedef std::map<std::string, InnerMap> OuterMap;

Data();

OuterMap & GetData()
{
return data;
}

InnerMap & GetData(const std::string &key)
{
return data[key];
}

private:
OuterMap data;
};

Data::Data()
{
const char *list[] = {"USA", "UK", "Japan", "Germany", "Russia", "India", 0};

for(const char **name=list; *name; ++name)
{
InnerMap &map = data.insert(OuterMap::value_type(*name, InnerMap())).first->second;

map.insert(InnerMap::value_type("1", "one"));
map.insert(InnerMap::value_type("2", "two"));
map.insert(InnerMap::value_type("3", "three"));
map.insert(InnerMap::value_type("4", "four"));
}
}

int main()
{
Data mainData;

Data::OuterMap &map = mainData.GetData();

for(Data::OuterMap::iterator i = map.begin(); i != map.end(); ++i)
{
std::cout << i->first << ':' << std::endl;

for(Data::InnerMap::iterator j = i->second.begin(); j != i->second.end(); ++j)
std::cout << " > " << j->first << "=" << j->second << std::endl;
}

return 0;
}




You probably won't care much for my coding style, but at least it runs.

FYI: std::map has two functions that might interest you: size() and empty(). No need to keep track of the size yourself.

Share this post


Link to post
Share on other sites

This topic is 4308 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Advertisement