Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #7498 > unrolled thread

STL map insert Options

Started bymrc2323@cox.net (Mike Copeland)
First post2011-07-05 14:13 -0700
Last post2011-07-19 15:20 +0000
Articles 11 — 7 participants

Back to article view | Back to comp.lang.c++


Contents

  STL map insert Options mrc2323@cox.net (Mike Copeland) - 2011-07-05 14:13 -0700
    Re: STL map insert Options Ian Collins <ian-news@hotmail.com> - 2011-07-06 10:28 +1200
    Re: STL map insert Options Paavo Helde <myfirstname@osa.pri.ee> - 2011-07-06 01:14 -0500
    Re: STL map insert Options Stephen Howe <stephen.howe@kantarmedia.com> - 2011-07-12 13:29 -0700
      Re: STL map insert Options Ian Collins <ian-news@hotmail.com> - 2011-07-13 09:01 +1200
        Re: STL map insert Options Stephen Howe <stephen.howe@kantarmedia.com> - 2011-07-13 07:31 -0700
          Re: STL map insert Options Leigh Johnston <leigh@i42.co.uk> - 2011-07-13 15:59 +0100
          Re: STL map insert Options Ian Collins <ian-news@hotmail.com> - 2011-07-14 07:57 +1200
            Re: STL map insert Options Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2011-07-14 00:07 -0400
              Re: STL map insert Options Ian Collins <ian-news@hotmail.com> - 2011-07-14 16:50 +1200
    Re: STL map insert Options Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-07-19 15:20 +0000

#7498 — STL map insert Options

Frommrc2323@cox.net (Mike Copeland)
Date2011-07-05 14:13 -0700
SubjectSTL map insert Options
Message-ID<MPG.287d2c69abea9b739896c0@news.eternal-september.org>
   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

[toc] | [next] | [standalone]


#7501

FromIan Collins <ian-news@hotmail.com>
Date2011-07-06 10:28 +1200
Message-ID<97hhh0Fo68U2@mid.individual.net>
In reply to#7498
On 07/ 6/11 09:13 AM, Mike Copeland wrote:
>     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));

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#7511

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2011-07-06 01:14 -0500
Message-ID<Xns9F1A5E16EDD59myfirstnameosapriee@216.196.109.131>
In reply to#7498
mrc2323@cox.net (Mike Copeland) wrote in news:MPG.287d2c69abea9b739896c0
@news.eternal-september.org:

Ian already answered your main questions I think, here are just some 
comments about typedefs.

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

The above typedef is not useful as you effectively create two names 
(ChipRec and TData) meaning the same thing, which can only cause 
confusion later. This technique is used only in C as in C the two names 
are not identic (one has to be always used with 'struct' keyword, the 
other not). When encountered in a C++ program, this is classified as a C-
ism.

 
>     TData tWork;
> 
> typedef map<int, ChipRec> BCI;

This typedef OTOH is useful as it helps to shorten other code and makes 
it easier to cope with changes (e.g. using a hash map instead of map).

>      BCI bci;
>      map<int, ChipRec>::iterator bciIter;

Should be BCI::iterator bciIter;

> int main()
> {
>     tWork.bibNum = 2066, tWork.cEvent = 'a', tWork.finTime = 0;
>     bci.insert(BCI::value_type(tWork.bibNum, tWork));

Why not 

bci[tWork.bibNum] = tWork; 

(OK, there are semantic differences if the key already exists.)

hth
Paavo

[toc] | [prev] | [next] | [standalone]


#7760

FromStephen Howe <stephen.howe@kantarmedia.com>
Date2011-07-12 13:29 -0700
Message-ID<526778d1-e768-4ee3-b42e-f8cc9444fab9@t8g2000prm.googlegroups.com>
In reply to#7498
Mike

The value_type insert is more efficient than pair() or make_pair()

See my response from an ancient thread in 2004
https://groups.google.com/group/microsoft.public.vc.stl/tree/browse_frm/thread/a5606c0102b2fd24/ee8b0301ba96661a

Stephen Howe

[toc] | [prev] | [next] | [standalone]


#7762

FromIan Collins <ian-news@hotmail.com>
Date2011-07-13 09:01 +1200
Message-ID<983r38FglrU1@mid.individual.net>
In reply to#7760
On 07/13/11 08:29 AM, Stephen Howe wrote:
> Mike
>
> The value_type insert is more efficient than pair() or make_pair()
>
> See my response from an ancient thread in 2004
> https://groups.google.com/group/microsoft.public.vc.stl/tree/browse_frm/thread/a5606c0102b2fd24/ee8b0301ba96661a

Really?

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

[toc] | [prev] | [next] | [standalone]


#7781

FromStephen Howe <stephen.howe@kantarmedia.com>
Date2011-07-13 07:31 -0700
Message-ID<a0b73b83-e7ac-431f-8778-ffcf1dd22c0e@h38g2000pro.googlegroups.com>
In reply to#7762
> 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

[toc] | [prev] | [next] | [standalone]


#7782

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-07-13 15:59 +0100
Message-ID<s7CdnemZZaMhL4DTnZ2dnUVZ8l6dnZ2d@giganews.com>
In reply to#7781
On 13/07/2011 15:31, Stephen Howe wrote:
>> 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
>>>

std::map's value_type is a typedef of a std::pair; if the pair type you 
are using is identical to this typedef then there should be no 
difference between value_type(foo, bar) and std::pair<foo_type, 
bar_type>(foo, bar).

HTH.

/Leigh

[toc] | [prev] | [next] | [standalone]


#7784

FromIan Collins <ian-news@hotmail.com>
Date2011-07-14 07:57 +1200
Message-ID<986bn2FglrU4@mid.individual.net>
In reply to#7781
On 07/14/11 02:31 AM, Stephen Howe wrote:

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

>> 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).

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>

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#7788

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2011-07-14 00:07 -0400
Message-ID<4e1e6bae$0$3476$c3e8da3$12bcf670@news.astraweb.com>
In reply to#7784
Ian Collins wrote:
> On 07/14/11 02:31 AM, Stephen Howe wrote:
>
> Please don't snip attributions, it's rude.
>
>>> 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).
>
> 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.

>
> <snip>
>

[toc] | [prev] | [next] | [standalone]


#7789

FromIan Collins <ian-news@hotmail.com>
Date2011-07-14 16:50 +1200
Message-ID<987av2F78bU2@mid.individual.net>
In reply to#7788
On 07/14/11 04:07 PM, Pavel wrote:
> Ian Collins wrote:
>> On 07/14/11 02:31 AM, Stephen Howe wrote:
>>>> 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).
>>
>> 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.

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.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#7973

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-07-19 15:20 +0000
Message-ID<slrnj2b85d.gtj.grahn+nntp@frailea.sa.invalid>
In reply to#7498
On Tue, 2011-07-05, Mike Copeland wrote:
>    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

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web