std::map associative container question

A

aaragon

Hello everyone,

I would like to know if there is a way to use the std::map to store
different types for one of its two types. That is, I'm trying to use
it as:

typedef std::map<string,double> Map;

but instead of double, I have integers, even booleans so I guess that
the use of double waste a lot of storage. Is there any way to do this?
Maybe with a typename?

Thank you all,

a^2
 
T

Thomas Tutone

aaragon wrote:

I would like to know if there is a way to use the std::map to store
different types for one of its two types. That is, I'm trying to use
it as:

typedef std::map<string,double> Map;

but instead of double, I have integers, even booleans so I guess that
the use of double waste a lot of storage. Is there any way to do this?
Maybe with a typename?

Take a look at boost::any. If that's no help, you may need to describe
a bit more what it is you are trying to do. By the way, although I can
see good reasons not to use doubles, why do you care about wasting
storage? Is the map really that big?

Best regards,

Tom
 
A

aaragon

Thomas said:
aaragon wrote:



Take a look at boost::any. If that's no help, you may need to describe
a bit more what it is you are trying to do. By the way, although I can
see good reasons not to use doubles, why do you care about wasting
storage? Is the map really that big?

Best regards,

Tom

Well, it's not that the map is big, but also when you request the key,
then the value is returned. Therefore, sometimes I'm expecting a bool
but instead I'm receiving a double (and I don't want to convert the
values nor put a specifier in front as (bool) for example). I was
wondering that maybe there is a templetized way to do this. For
example,

template<typename T>
....
typedef std::map<string,T> Map;

but I don't think it may work.....
 
K

Kai-Uwe Bux

aaragon said:
Hello everyone,

I would like to know if there is a way to use the std::map to store
different types for one of its two types. That is, I'm trying to use
it as:

typedef std::map<string,double> Map;

but instead of double, I have integers, even booleans so I guess that
the use of double waste a lot of storage. Is there any way to do this?

The short answer is: no. The long answer is: yes, but the overhead incurred
be the logic needed to arrange for one object to represent values from
possible different types is very likely going to null and void all possible
gains in storage consumption.

E.g., you could do something like:

struct number {
~number();
};

struct number_double : public base {
double value;
};

struct number_int : public base {
int value;
};

....

std::map<string,number*> Map;

Then you have the overhead of one pointer per object and a real hassle to
sort out which object has which type (using dynamic_cast or some such
thing). In order for that to work, number needs to be polymorphic, which
usually means you have a vtable pointer. Given that heap allocation occurs
in chunks determined by the algorithm for new, we might already look at 20
to 36 bytes per entry in the map.

Have you verified that you really cannot afford the memory overhead from
converting everything to double, or are you engaging in premature
optimization?


Best

Kai-Uwe Bux
 
T

Thomas Tutone

aaragon said:
Well, it's not that the map is big, but also when you request the key,
then the value is returned. Therefore, sometimes I'm expecting a bool
but instead I'm receiving a double (and I don't want to convert the
values nor put a specifier in front as (bool) for example). I was
wondering that maybe there is a templetized way to do this. For
example,

template<typename T>
...
typedef std::map<string,T> Map;

but I don't think it may work.....

No, that definitely won't work. C++ is a strongly typed language, and
you need to instantiate the map using a particular type. As I said,
look at boost::any (see www.boost.org). Or maybe you can just do
something like the following:

struct Aaragon_multi_type {
int i;
double d;
bool b;
};

std::map<std::string, Aaragon_multi_type map;

Not space efficient, but would let store value of any of those in the
map...

Again, if you don't tell us what it is you want to do - i.e., why do
you want to store different types? - it's awfully hard to provide
useful advice.

Best regards,

Tom
 
A

aaragon

Kai-Uwe Bux said:
The short answer is: no. The long answer is: yes, but the overhead incurred
be the logic needed to arrange for one object to represent values from
possible different types is very likely going to null and void all possible
gains in storage consumption.

E.g., you could do something like:

struct number {
~number();
};

struct number_double : public base {
double value;
};

struct number_int : public base {
int value;
};

...

std::map<string,number*> Map;

Then you have the overhead of one pointer per object and a real hassle to
sort out which object has which type (using dynamic_cast or some such
thing). In order for that to work, number needs to be polymorphic, which
usually means you have a vtable pointer. Given that heap allocation occurs
in chunks determined by the algorithm for new, we might already look at 20
to 36 bytes per entry in the map.

Have you verified that you really cannot afford the memory overhead from
converting everything to double, or are you engaging in premature
optimization?


Best

Kai-Uwe Bux

Yes, I'm trying to write the code as optimal as possible from the
beginning. It is not that I have a big map. I'm trying to build a
genetic algorithm library so I decided to store all the possible
variables of the problem in a map. These variables include from
population size (an unsigned int) to probabilities of crossover and
mutation (double variables), or even boolean types (to see if a random
seed was given). I thought it would be cool to have everything in an
associative container so when I type map[popSize] then I get the
population size of the problem. However, as you can see the types are
different. What I'm doing right now is
typedef std::map<string,double> Map;
so when I need an unsigned int for example, I put an identifier in
front (size_t)Map[popSize]. This works but I thought it was a better
way to do this.
I never thought that having a map for different types was as
complicated as this. Thank you guys for your help.
 
J

jois.de.vivre

Thomas said:
No, that definitely won't work. C++ is a strongly typed language, and
you need to instantiate the map using a particular type. As I said,
look at boost::any (see www.boost.org). Or maybe you can just do
something like the following:

struct Aaragon_multi_type {
int i;
double d;
bool b;
};

std::map<std::string, Aaragon_multi_type map;

Not space efficient, but would let store value of any of those in the
map...

What if you used union instead of struct? That would be more space
efficient.
 
J

Jens Theisen

aaragon said:
typedef std::map<string,double> Map;
so when I need an unsigned int for example, I put an identifier in
front (size_t)Map[popSize]. This works but I thought it was a better
way to do this.

Is there a reason why you can't use different maps? I can think of
cases where you can't, or don't want to, but I suspect that you
actually should better do.

Frankly, I think that the language making it hard for you to follow
your approach is a sign that you're trying to do the wrong thing.

You want to store a variable popSize as a value of a map. Is there a
reason why you can't use a proper variable: size_t popSize? Do you
have an arbitrary number of those? How are they used?

If you could post some code of what you're really trying to do, this
would help a lot.
I never thought that having a map for different types was as
complicated as this.

It's simple with boost::any, and for double, int and bool alone a
union is also a possibility. However, this is most certainly not want
you want to do.
Yes, I'm trying to write the code as optimal as possible from the
beginning. It is not that I have a big map.

You know that early optimisation is the source of all evil, do you?
But that's a different matter.

Jens
 
A

aaragon

Jens said:
aaragon said:
typedef std::map<string,double> Map;
so when I need an unsigned int for example, I put an identifier in
front (size_t)Map[popSize]. This works but I thought it was a better
way to do this.

Is there a reason why you can't use different maps? I can think of
cases where you can't, or don't want to, but I suspect that you
actually should better do.

Well, the only reason was to refer to all the parameters of the problem
with a single map. I did think about the possibility to having
different maps to hold different variable types but then I thought that
maybe there was a better way to do it.
Frankly, I think that the language making it hard for you to follow
your approach is a sign that you're trying to do the wrong thing.

You want to store a variable popSize as a value of a map. Is there a
reason why you can't use a proper variable: size_t popSize? Do you
have an arbitrary number of those? How are they used?

I didn't want to store the variables in the proper way, because I think
that at some stage of the code I will be accesing the same variables
from different locations (and different objects will be accesing these
variables as well). Also, there are some variables that do not belong
to any single object.
If you could post some code of what you're really trying to do, this
would help a lot.


It's simple with boost::any, and for double, int and bool alone a
union is also a possibility. However, this is most certainly not want
you want to do.

I'll try this boost::any =)
You know that early optimisation is the source of all evil, do you?
But that's a different matter.

I didn't know this... why???????
 
J

Jens Theisen

aaragon said:
Well, the only reason was to refer to all the parameters of the problem
with a single map. I did think about the possibility to having
different maps to hold different variable types but then I thought that
maybe there was a better way to do it.

Do you have experience with dynamically typed languages such as Perl
or Python? In those, you do exactly what you're trying to do in C++.

You might not want to heed this advice, but I urge you: Let the type
system be your friend; don't use boost::any unless absolutely
necessary and rather use multiple maps, or even better, simple
variables as long as that's sufficient.

Don't cast around, especially not with C-style casts ( as in
(int)myvar ).

The type system is a feature of C++, not a nuisance. It pulls the
logic of your program together so that it doesn't fall apart.
Also, there are some variables that do not belong
to any single object.

Because there are global? Make them either global then, or have some
object that contains what's effectively global storage. Refactor it
when it gets too big.
I'll try this boost::any =)

Resist! :)
I didn't know this... why???????

Because

1. you will not be successful (you don't know what will make your
program slow when it will eventually be)

but

2. you will waste resources in the try and probably also compromise
other design goals such as correctness.

I know that it's difficult not to early optimisation, but I'm
convinced it's wise.

Regards,

Jens
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

aaragon said:
Yes, I'm trying to write the code as optimal as possible from the
beginning. It is not that I have a big map. I'm trying to build a
genetic algorithm library so I decided to store all the possible
variables of the problem in a map. These variables include from
population size (an unsigned int) to probabilities of crossover and
mutation (double variables), or even boolean types (to see if a random

I think that to store the variables in a map, and then searching for them at
runtime, will be a lot slower that using member variables and let the
compiler do the job a compile time. What are you trying to optimize?
 
A

aaragon

Jens said:
Do you have experience with dynamically typed languages such as Perl
or Python? In those, you do exactly what you're trying to do in C++.

You might not want to heed this advice, but I urge you: Let the type
system be your friend; don't use boost::any unless absolutely
necessary and rather use multiple maps, or even better, simple
variables as long as that's sufficient.

Don't cast around, especially not with C-style casts ( as in
(int)myvar ).

What is wrong with doing C casts? what could go wrong?
The type system is a feature of C++, not a nuisance. It pulls the
logic of your program together so that it doesn't fall apart.


Because there are global? Make them either global then, or have some
object that contains what's effectively global storage. Refactor it
when it gets too big.

I thought that working without global variables is a must in C++.
Resist! :)


Because

1. you will not be successful (you don't know what will make your
program slow when it will eventually be)

but

2. you will waste resources in the try and probably also compromise
other design goals such as correctness.

I know that it's difficult not to early optimisation, but I'm
convinced it's wise.

Regards,

Jens

Thanks for the tips Jens. I'll follow your advise. I'll use private
member variables to store the variables.
 
A

aaragon

Julián Albo said:
I think that to store the variables in a map, and then searching for them at
runtime, will be a lot slower that using member variables and let the
compiler do the job a compile time. What are you trying to optimize?

I'm writing a code to optimize 2D and 3D networks with genetic
algorithms.
 
T

Thomas J. Gritzan

aaragon said:
I'll try this boost::any =)

I would suggest using boost::variant instead of boost::any, because I found
it more usefull, and maybe faster.

boost::variant stores, just like boost::any, one value but of a specific
set of types, just like a union, but in a typesafe way.

Unlike boost::any, you can use a generic visitor pattern for
boost::variant, what makes it more usefull, since you don't have to go with
switch() or if()/else() constructs for every type that could be stored.

Just read the documentation of both at the boost website and compare.
 
A

aaragon

Thomas said:
I would suggest using boost::variant instead of boost::any, because I found
it more usefull, and maybe faster.

boost::variant stores, just like boost::any, one value but of a specific
set of types, just like a union, but in a typesafe way.

Unlike boost::any, you can use a generic visitor pattern for
boost::variant, what makes it more usefull, since you don't have to go with
switch() or if()/else() constructs for every type that could be stored.

Just read the documentation of both at the boost website and compare.

I'll take a look... thank you Thomas...
 
J

Jens Theisen

aaragon said:
What is wrong with doing C casts? what could go wrong?

This advice is not as important as the other, though. C-style casts do
allow too much, as in

struct A { };
struct B : A { };
struct C : A { };

int main()
{
B * ptr = new B;
C * ptr2 = ( C* )(ptr);
}

which static_cast would no allow. Also, when using static_cast and
const_cast, constness is separated from the other kinds of casted
leading to a cleaner style.

However, I admit that this is not a particularly strong argument. Does
anyone have a more compelling example of what frequently goes wrong
with C-style casts?
I thought that working without global variables is a must in C++.

Clearly global storage is undesirable, but there are always tradeoffs
and there are more important things to get right. Important is that
your globabl variables are all conceptually constant. For example, a
global cache for something might be okay, as the caches presence
should be transparant to the rest of the logic - the program should
behave as there was no cache.

I you post some code after you played around a little bit, I'm sure
you'll get a free code review here. :)

Regards,

Jens
 
A

aaragon

Jens said:
This advice is not as important as the other, though. C-style casts do
allow too much, as in

struct A { };
struct B : A { };
struct C : A { };

int main()
{
B * ptr = new B;
C * ptr2 = ( C* )(ptr);
}

which static_cast would no allow. Also, when using static_cast and
const_cast, constness is separated from the other kinds of casted
leading to a cleaner style.

However, I admit that this is not a particularly strong argument. Does
anyone have a more compelling example of what frequently goes wrong
with C-style casts?


Clearly global storage is undesirable, but there are always tradeoffs
and there are more important things to get right. Important is that
your globabl variables are all conceptually constant. For example, a
global cache for something might be okay, as the caches presence
should be transparant to the rest of the logic - the program should
behave as there was no cache.

I you post some code after you played around a little bit, I'm sure
you'll get a free code review here. :)

Regards,

Jens

Thanks Jens! I appreciate it... =)
 
D

Diego Martins

Kai-Uwe Bux said:
The short answer is: no. The long answer is: yes, but the overhead incurred
be the logic needed to arrange for one object to represent values from
possible different types is very likely going to null and void all possible
gains in storage consumption.

E.g., you could do something like:

struct number {
~number();
};

virtual ~number(); , instead
struct number_double : public base {
double value;
};

struct number_int : public base {
int value;
};

public number, instead of public base
...

std::map<string,number*> Map;

Kai, don't get me wrong. Actually, I know it was only typos, but my
intention is help the OP.

Diego Martins
HP
 
V

Victor Bazarov

Diego said:
Kai, don't get me wrong. Actually, I know it was only typos, but my
intention is help the OP.

The name you should have used is "Kai-Uwe", not "Kai". Don't get me
wrong, Diego.
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top