STL map of structures

B

Bob Altman

Hi all,

I have a structure that includes a constructor. I want to add a bunch of these
structures to an STL map (whose index is an int). If I define the map like
this:

map<int, MyStruct*> myMap;

then I can add pointers to newly allocated structures like this:

myMap[index] = new MyStruct(constructorArguments);

The downside of this is that now I have a map of pointers to structures and I'm
stuck with an extra indirection whenever I access the map, which just adds a bit
of obfuscation to the code. Is there an easy way to actually declare the map
like this:

map<int, MyStruct> MyMap

and then add newly constructed structures (not pointers to structures) to the
map?

TIA - Bob
 
D

Doug Harrison [MVP]

Hi all,

I have a structure that includes a constructor. I want to add a bunch of these
structures to an STL map (whose index is an int). If I define the map like
this:

map<int, MyStruct*> myMap;

then I can add pointers to newly allocated structures like this:

myMap[index] = new MyStruct(constructorArguments);

The downside of this is that now I have a map of pointers to structures and I'm
stuck with an extra indirection whenever I access the map, which just adds a bit
of obfuscation to the code. Is there an easy way to actually declare the map
like this:

map<int, MyStruct> MyMap

and then add newly constructed structures (not pointers to structures) to the
map?

If MyStruct supports copying (has accessible copy ctor and assignment
operator, either implicit or user-defined), you're all set.
 
D

David Lowndes

I have a structure that includes a constructor. I want to add a bunch of these
structures to an STL map (whose index is an int). If I define the map like
this:

map<int, MyStruct*> myMap;

then I can add pointers to newly allocated structures like this:

myMap[index] = new MyStruct(constructorArguments);

The downside of this is that now I have a map of pointers to structures and I'm
stuck with an extra indirection whenever I access the map, which just adds a bit
of obfuscation to the code. Is there an easy way to actually declare the map
like this:

map<int, MyStruct> MyMap

and then add newly constructed structures (not pointers to structures) to the
map?

Something like this perhaps:

struct MyStruct
{
int m_i;
MyStruct( int Val )
{
m_i = Val;
}
MyStruct()
{
}
};

int _tmain(int argc, _TCHAR* argv[])
{
map<int, MyStruct> MyMap;
MyMap[12] = MyStruct(12);
MyMap[3] = MyStruct(3);
....
}

Dave
 
D

Doug Harrison [MVP]

Something like this perhaps:

struct MyStruct
{
int m_i;
MyStruct( int Val )
{
m_i = Val;
}
MyStruct()
{
}
};

int _tmain(int argc, _TCHAR* argv[])
{
map<int, MyStruct> MyMap;
MyMap[12] = MyStruct(12);
MyMap[3] = MyStruct(3);
...
}

That's right; MyStruct needs a default constructor in addition to being
copyable in order to support:

MyMap[12] = MyStruct(12);

This is pretty atypical for STL, though, and usually types stored in
containers don't require a default ctor.
 
B

Bob Altman

Something like this perhaps:
struct MyStruct
{
int m_i;
MyStruct( int Val )
{
m_i = Val;
}
MyStruct()
{
}
};

int _tmain(int argc, _TCHAR* argv[])
{
map<int, MyStruct> MyMap;
MyMap[12] = MyStruct(12);
MyMap[3] = MyStruct(3);
...
}

That's right; MyStruct needs a default constructor in addition to being
copyable in order to support:

MyMap[12] = MyStruct(12);

This is pretty atypical for STL, though, and usually types stored in
containers don't require a default ctor.

I assume that when you say the struct needs to be "copyable" you are actually
saying that I need to add a copy constructor, which isn't shown in the example
above. Is that correct?
 
B

Bob Altman

So, here's the related philosophical question: Is there a compelling reason to
have a map of structures as opposed to a map of pointers to structures? I guess
if I have a map of pointers to structures then I'll end up allocating structures
from the heap in addition to whatever heap allocations the map class uses for
its own internal data structures. And the esthetic advantage of having a map of
structures is that I don't have to dereference an additional pointer to get to
my data. The downside (such as it is) of having a map of structures is having
to add a default constructor and a copy constructor to my structure.
 
D

Doug Harrison [MVP]

Something like this perhaps:

struct MyStruct
{
int m_i;
MyStruct( int Val )
{
m_i = Val;
}
MyStruct()
{
}
};

int _tmain(int argc, _TCHAR* argv[])
{
map<int, MyStruct> MyMap;
MyMap[12] = MyStruct(12);
MyMap[3] = MyStruct(3);
...
}

That's right; MyStruct needs a default constructor in addition to being
copyable in order to support:

MyMap[12] = MyStruct(12);

This is pretty atypical for STL, though, and usually types stored in
containers don't require a default ctor.

I assume that when you say the struct needs to be "copyable" you are actually
saying that I need to add a copy constructor, which isn't shown in the example
above. Is that correct?

Like I said in my first post, it can be either explicit or implicit.
David's example contained nothing to prevent the compiler from generating
it (along with the assignment operator), and his example class contains
nothing that would require you to circumvent what the compiler will do
automatically, so it's fine to rely on the default copy ctor in this case.
 
D

Doug Harrison [MVP]

So, here's the related philosophical question: Is there a compelling reason to
have a map of structures as opposed to a map of pointers to structures? I guess
if I have a map of pointers to structures then I'll end up allocating structures
from the heap in addition to whatever heap allocations the map class uses for
its own internal data structures. And the esthetic advantage of having a map of
structures is that I don't have to dereference an additional pointer to get to
my data. The downside (such as it is) of having a map of structures is having
to add a default constructor and a copy constructor to my structure.

I agree that's not much of a downside. Storing objects as opposed to
pointers to dynamically allocated objects is usually preferable, because:

1. Objects will be destroyed when erased from the container, while you'll
have to delete pointers when you erase them.

2. It's easier to be exception-safe.

3. There's less overhead, and it may be faster.

When there's a legitimate choice, the major reason to store pointers to
dynamically allocated objects instead of the objects themselves is due to
the objects being very expensive to copy, e.g. because of size. Of course,
if the objects aren't copyable, or you need them to appear in multiple data
structures, you have to use pointers.
 
C

Charles Wang [MSFT]

Hi Bob,
I believe that Doug had provided concise and helpful answers here. I just
would like to add additional comments regarding one of your concerns, "The
downside (such as it is) of having a map of structures is having
to add a default constructor and a copy constructor to my structure.".

Generally you need not to add a default constructor and a copy constructor
to your structure since complier will do it implicitly (mostly bitwise
copy). You can simply perform a test with the following code:
struct MyStruct
{
int m_i;
int* p_i;
};

int _tmain(int argc, _TCHAR* argv[])
{
MyStruct s;
int n = 100;
s.m_i = 10;
s.p_i = &n;


map<int, MyStruct> myMap;
myMap[0]=s;
printf("%d,%d",myMap[0].m_i,*(myMap[0].p_i));

getchar();
return 0;
}

Whether or not to use a copy constructor depends on situations. When a
class does not allow/need to use bitwise copy semantics, you need to
explicitly write a copy constructor. I would like to recommend a famous
book (written by Stanley B.Lippman) for you "Inside The C++ Object Model"
(http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545).
You can read the chapter "The senmantics of constructors" in which Stanley
listed four typical situations that do not need "Bitwise Copy Semantics".
Generally they are the following:
1) Member class object having copy constructor
2) Base class having copy constructor
3) Class having one or more virtual functions
4) Derived class having one or more virtual base classes

Hope this helps.

Best regards,
Charles Wang
Microsoft Online Community Support
===========================================================
Delighting our customers is our #1 priority. We welcome your
comments and suggestions about how we can improve the
support we provide to you. Please feel free to let my manager
know what you think of the level of service provided. You can
send feedback directly to my manager at: (e-mail address removed).
===========================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for
non-urgent issues where an initial response from the community
or a Microsoft Support Engineer within 1 business day is acceptable.
Please note that each follow up response may take approximately
2 business days as the support professional working with you may
need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by
contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
============================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
=========================================================
 
B

Bob Altman

Thanks a million! After all that, it turns out that my original problem was
that my structure had a parameterized constructor but I neglected to give it
a default (parameterless) constructor. When I tried adding a new structure
to my map:

MyMap = MyStruct(constructorArgs);

the compiler complained that "no appropriate default constructor is
available", but I didn't know what that meant. Now that I've been
reeducated (as in "I used to know this but I forgot", as opposed to
"brainwashed") I realize that the compiler will give me a free copy
constructor but I need to make sure that it has access to a default
constructor, which I must explicitly provide if I also provide a non-default
constructor.

Anyway, thanks again for the considerable help!

Bob
 
A

adebaene

When there's a legitimate choice, the major reason to store pointers to
dynamically allocated objects instead of the objects themselves is due to
the objects being very expensive to copy, e.g. because of size.

...or because you are storing polymorphic objects in the container (eg,
base class pointers which are pointing to derived objects).

Arnaud
 
D

Doug Harrison [MVP]

..or because you are storing polymorphic objects in the container (eg,
base class pointers which are pointing to derived objects).

That's certainly true, but in that case, you really don't have any choice,
legitimate or otherwise. Some other reasons to store pointers include:

1. Object needs to be referenced from multiple containers.

2. Object can be NULL (sometimes useful for associative containers).
 

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

Top