STL map insert Options

M

Mike Copeland

I am curious about the benefits of several STL map usages and
interfaces. Consider the following declarations:

class Entrant
{
public:
int baseBib;
char baseEvent;
unsigned int specTime;
} ;

int main()
{
map<int, Entrant> myEntrant;
map<int, Entrant>::iterator it;
Entrant a1;

a1.baseBib = 2066, a1.baseEvent = 'a', a1.specTime = 0;
myEntrant.insert(pair<int, Entrant>(a1.baseBib, a1));
[etc.]

....and:

typedef struct ChipRec
{
int bibNum;
char cEvent;
unsigned int finTime;
} TData;
TData tWork;

typedef map<int, ChipRec> BCI;
BCI bci;
map<int, ChipRec>::iterator bciIter;
int main()
{
tWork.bibNum = 2066, tWork.cEvent = 'a', tWork.finTime = 0;
bci.insert(BCI::value_type(tWork.bibNum, tWork));
[etc.]

In both declarations I'm doing the same work, but I can't see any
advantage to either (class or typedef struct declarations)...other than
minor coding differences. Am I missing something that _is_ a reason to
use one technique versus another?
Also, I see some references to "make_pair", but I don't understand
what that is nor why/how I might use that construct in my applications.
Could someone explain the 3 constructs "pair", "make_pair" and
"value_type"? TIA
 
I

Ian Collins

I am curious about the benefits of several STL map usages and
interfaces. Consider the following declarations:

class Entrant
{
public:
int baseBib;
char baseEvent;
unsigned int specTime;
} ;

int main()
{
map<int, Entrant> myEntrant;
map<int, Entrant>::iterator it;
Entrant a1;

a1.baseBib = 2066, a1.baseEvent = 'a', a1.specTime = 0;
myEntrant.insert(pair<int, Entrant>(a1.baseBib, a1));
[etc.]

....and:

typedef struct ChipRec
{
int bibNum;
char cEvent;
unsigned int finTime;
} TData;
TData tWork;

typedef map<int, ChipRec> BCI;
BCI bci;
map<int, ChipRec>::iterator bciIter;
int main()
{
tWork.bibNum = 2066, tWork.cEvent = 'a', tWork.finTime = 0;
bci.insert(BCI::value_type(tWork.bibNum, tWork));
[etc.]

In both declarations I'm doing the same work, but I can't see any
advantage to either (class or typedef struct declarations)...other than
minor coding differences. Am I missing something that _is_ a reason to
use one technique versus another?
Also, I see some references to "make_pair", but I don't understand
what that is nor why/how I might use that construct in my applications.
Could someone explain the 3 constructs "pair", "make_pair" and
"value_type"? TIA

The value_type for a std::map is a std::pair<key,value>.

std::make_pair is a function template short cut for creating a
std::pair. The function template allows automatic template argument
deduction. So

myEntrant.insert(std::pair<int, Entrant>(a1.baseBib, a1));

is equivalent to

myEntrant.insert(std::make_pair(a1.baseBib, a1));
 
S

Stephen Howe

I'd be very surprised if all three didn't compile down to the same
assembly code.  It certainly does with the two compilers I tried.

Ian Collins

I have just rechecked with Visual Studio 2008, 8 years later and I get
the same results.
And that is with full optimisations switched on.
It is easy to see why as make_pair()/pair() are creating an actual
object to insert, value_type does not. So that is an extra round of
copy constructors/destructors.
You might be using ints and the compilers you use might optimise out
extra assignments.

With the code referenced in the link, I get (and it is not too hard to
work out what work map actually does).
make_pair test Start
Value copy ctor
Key copy ctor
Key copy ctor
Value copy ctor
Key dtor
Value dtor
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Value dtor
Key dtor
Value dtor
Key dtor
make_pair test Stop

pair test Start
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Value dtor
Key dtor
Value dtor
Key dtor
pair test Stop

value_type test Start
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Value dtor
Key dtor
value_type test Stop

pre-formed pair test Start
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Value dtor
Key dtor
pre-formed pair test Stop

[] test insert Start
Value dflt ctor
Key copy ctor
Value copy ctor
Key copy ctor
Value copy ctor
Value dtor
Key dtor
Value dtor
Value assignment
[] test insert Stop

pre-formed pair failure test Start
Key copy ctor
Value copy ctor
Value dtor
Key dtor
pre-formed pair failure test Stop

[] test update Start
Value assignment
[] test update Stop
Stephen Howe
 
I

Ian Collins

On 07/14/11 02:31 AM, Stephen Howe wrote:

Please don't snip attributions, it's rude.
I have just rechecked with Visual Studio 2008, 8 years later and I get
the same results.
And that is with full optimisations switched on.
It is easy to see why as make_pair()/pair() are creating an actual
object to insert, value_type does not. So that is an extra round of
copy constructors/destructors.
You might be using ints and the compilers you use might optimise out
extra assignments.

With the code referenced in the link, I get (and it is not too hard to
work out what work map actually does).

If you change the code to use the same type as the map::value_type, all
things are equal. For example:

m.insert(pair<const Key, Value>(t2, tv));

<snip>
 
P

Pavel

Ian said:
On 07/14/11 02:31 AM, Stephen Howe wrote:

Please don't snip attributions, it's rude.


If you change the code to use the same type as the map::value_type, all things
are equal. For example:

m.insert(pair<const Key, Value>(t2, tv));
const is the key here; otherwise there will be the second copy; same with make_pair.

e.g. reasonably looking


std::map<int, int> m;
m.insert(std::make_pair(1,2));

will lead to 2 copies: first std::pair<int, int>(), then std::pair<const int,
int>(std::pair<int, int>);

That's why for performance reasons, value_type or a typedef is a better option.
For same reason make_pair is one of the "evil" functions that I never use: it's
too easy to introduce an accidental extra copy.
 
I

Ian Collins

const is the key here; otherwise there will be the second copy; same with make_pair.

e.g. reasonably looking


std::map<int, int> m;
m.insert(std::make_pair(1,2));

will lead to 2 copies: first std::pair<int, int>(), then std::pair<const int,
int>(std::pair<int, int>);

That's why for performance reasons, value_type or a typedef is a better option.
For same reason make_pair is one of the "evil" functions that I never use: it's
too easy to introduce an accidental extra copy.

Indeed. A little helper like

template <typename Key, typename Value>
std::pair<const Key,Value> map_pair( const Key& key, Value& value )
{
return std::pair<const Key,Value>(key, value);
}

can come in handy.
 
J

Jorgen Grahn

I am curious about the benefits of several STL map usages and
interfaces. Consider the following declarations: ....
myEntrant.insert(pair<int, Entrant>(a1.baseBib, a1)); ....
bci.insert(BCI::value_type(tWork.bibNum, tWork)); ....
Also, I see some references to "make_pair", but I don't understand
what that is nor why/how I might use that construct in my applications.

It's just a helper function which you can use instead of the std::pair
constructor to save some typing (you don't have to spell out the
template argument names). I never thought of using the map's
value_type instead, but that's probably more elegant!

/Jorgen
 

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

Similar Threads

Modify STL map Object 4
Changing STL map Object Data 4
STL map find_if 5
Sorting an STL map 1
STL set Problem 5
Building a Large Container 26
STL::MAP: Printing values only once .. 9
What Am I Doing Wrong? 7

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top