STL: Map of List of Pointers

G

gthorne

Ok, so I'm trying to code a map of lists of pointers to a class (that
contains a struct). Basically, the class holds the struct that I'm
populating, and there can be multiple of these. The declaration looks
like this:
map<int, list<my_class*> > map_test;

Now, how do I go about adding and accessing a new element to any given
list? How would I access the data? I did this with a list of
pointers, but can't figure out how to get the map into the equation.
My 'list' code looked like this:

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

using namespace std;

class ex_class
{
public:
struct
{
int num;
int num2;
} info;

int inc_num () {return ++info.num;}
int dec_num () {return --info.num;}
int add_nums () {return info.num + info.num2;}
void print_vals ()
{
cout << "num: " << info.num << " num2: " << info.num2 << "\n\n";
}
};

int main ()
{
list<ex_class*> class_list, anon_list;
list<ex_class*>::iterator class_it, anon_it;
map<int, list<ex_class*>> map_test;
ex_class classone;
classone.info.num = 40;
classone.info.num2 = 30;
classone.print_vals();
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << "Sum: " << classone.add_nums() << "\n\n";

class_list.push_back (&classone);
class_it=class_list.begin();
(*class_it)->info.num = 20;
(*class_it)->print_vals();

anon_list.push_back (new ex_class);
anon_it=anon_list.begin();
(*anon_it)->info.num = 33;
(*anon_it)->info.num2 = 77;
(*anon_it)->print_vals();

return 0;
}


Any help would be great!
 
M

Mike Wahler

Ok, so I'm trying to code a map of lists of pointers to a class (that
contains a struct). Basically, the class holds the struct that I'm
populating, and there can be multiple of these. The declaration looks
like this:
map<int, list<my_class*> > map_test;

Now, how do I go about adding and accessing a new element to any given
list? How would I access the data? I did this with a list of
pointers, but can't figure out how to get the map into the equation.
My 'list' code looked like this:

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

#include said:
using namespace std;

class ex_class
{
public:
struct
{
int num;
int num2;
} info;

int inc_num () {return ++info.num;}
int dec_num () {return --info.num;}
int add_nums () {return info.num + info.num2;}
void print_vals ()
{
cout << "num: " << info.num << " num2: " << info.num2 << "\n\n";
}
};

int main ()
{
list<ex_class*> class_list, anon_list;
list<ex_class*>::iterator class_it, anon_it;
map<int, list<ex_class*>> map_test;

This line won't compile. Make it:

map said:
ex_class classone;
classone.info.num = 40;
classone.info.num2 = 30;
classone.print_vals();
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << classone.inc_num() << '\n';
cout << "Sum: " << classone.add_nums() << "\n\n";

class_list.push_back (&classone);
class_it=class_list.begin();
(*class_it)->info.num = 20;
(*class_it)->print_vals();

anon_list.push_back (new ex_class);
anon_it=anon_list.begin();
(*anon_it)->info.num = 33;
(*anon_it)->info.num2 = 77;
(*anon_it)->print_vals();

map_test.insert(pair<int, list<ex_class*> >(42, class_list));
map_test.insert(pair<int, list<ex_class*> >(99, anon_list));

list<ex_class*>::const_iterator it(map_test[42].begin());
cout << (**it).info.num << '\n';

/* 42 and 99 are arbitrary values */

-Mike
 
G

gthorne

Mike-
Thanks for the speedy reply, and help. I have two more questions. Is
there a way to do something like this so I wouldn't have to use an
intermediate object? (I know this probably doesn't compile,it's just an
example to give you an idea of what I want to do):

map_test.insert(pair<int, list<ex_class*> >(43, new ex_class);

Also, how would I reference the struct in the class?
 
M

Mike Wahler

gthorne said:
Mike-
Thanks for the speedy reply, and help. I have two more questions. Is
there a way to do something like this so I wouldn't have to use an
intermediate object? (I know this probably doesn't compile,it's just an
example to give you an idea of what I want to do):

map_test.insert(pair<int, list<ex_class*> >(43, new ex_class);

You can't do that because the second template parameter is
a pointer to a list, not a pointer to an 'ex_class'. Also
note that this still uses an 'intermediate' (more formally,
a 'temporary') object, that is, the pointer object returned
by the 'new' operator
However you could first insert empty lists into your map,
and then insert 'ex_class' objects into those lists after
the fact.
Also, how would I reference the struct in the class?

See the last 'cout' statement in my example.

(BTW, in my last post, I forget to
advise you that you should 'delete' any objects which you've
allocate with 'new', when done with them. Your code you
posted did not do that).

-Mike
 
?

=?iso-8859-1?Q?Ali_=C7ehreli?=

Is
there a way to do something like this so I wouldn't have to use an
intermediate object? (I know this probably doesn't compile,it's just an
example to give you an idea of what I want to do):

map_test.insert(pair<int, list<ex_class*> >(43, new ex_class);

First, I suggest that you get into the habit of using typedefs to make your
code more clear. This would also avoid your earlier error that was corrected
by Mike Wahler.

class Foo{ /* ... */};

typedef list<Foo*> Foos;
typedef map<int, Foos> FoosDictionary;

Adding make_pair to this, we get a much more readable code:

Foos anon_foos;
FoosDictionary foosDictionary;
foosDictionary.insert(make_pair(42, anon_foos));

As you've observed, this takes a copy of anon_foos and stores that copy in
the dictionary. In order to get what you asked, write a function that
returns an ex_class*, and call it when calling make_pair:

ex_class * prepare_ex_class(/* ... */)
{
ex_class * object = new ex_class(/* ... */);
// do other things to object ...
return object;
}

Then, when you insert:

map_test.insert(make_pair(43, prepare_ex_class(/* ... */));

But then you should change the definition of the dictionary:

typedef map<int, Foos *> FoosDictionary;

Be warned though, these are not exception safe. A common safe way of storing
dynamic objects in standard containers is to store smart pointers instead of
plain pointers. Even your list<Foo*> could benefit from a smart pointer:

#include <boost/shared_ptr.hpp>

using namespace boost;

/* ... */

typedef shared_ptr<Foo> FooPtr;
typedef list<FooPtr> Foos;
typedef shared_ptr<Foos> FoosPtr;
typedef map<int, FoosPtr> FoosDictionary;

// etc. :)

Ali
 
G

gthorne

Ali/Mike-
Thanks for your great replies. As for 'delete' and the typedefs, those
are coming. What I posted above was just sample code that I was
tinkering with to get this to work.

Do you think it may be better to put the list inside of the class?
Basically, without getting into the specific (i.e. 'boring') business
need for this code, think of it as a grocery store checkout (that's not
what it is, but it's a good example). The class holds the information
for one item. The list is the multiple items that the cashier is
ringing up, and the map is the multiple lanes. Should it be 'map of
lists of pointers to classes containing a struct', or 'map of pointers
to classes containing lists of structs'?

You guys have been a great help, and I appreciate it very much.
 
?

=?iso-8859-1?Q?Ali_=C7ehreli?=

As for 'delete' and the typedefs, those
are coming.

Note that, if you go the smart pointer route, you highly likely won't need
to delete explicitly. boost::shared_ptr, which is also a standard library
feature after TR1, deletes the objects it owns automatically.

As for the class design, given what you describe, I picture it as the
following:
The class holds the information
for one item.

class Item {/* ... */};
The list is the multiple items that the cashier is
ringing up,

Simply:

typedef list<Item> GroceryBag;

or, if it needs more logic:

class GroceryBag
{
list<Item> items_;
Color color_; // "colour" works too :)
// etc.

/* ... */
};
and the map is the multiple lanes.

class Cashier
{
/* ... */

public:

void process(GroceryBag const & groceryBag);

/* ... */
};

typedef map<int, Cashier> Cashiers;

class Shopper
{
GroceryBag bag_;

/* ... */

public:

void check_out(Cashier const & cashier)
{
cashier.process(bag_);
}
};

Cashier & least_busy_cashier(Cashiers & cashiers)
{
return /* one of the cashiers */
}

customer.check_out(least_busy_cashier(cashiers));
Should it be 'map of
lists of pointers to classes containing a struct', or 'map of pointers
to classes containing lists of structs'?

I don't see any reason for pointers in what you described.

Ali
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top