Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #7498 > unrolled thread
| Started by | mrc2323@cox.net (Mike Copeland) |
|---|---|
| First post | 2011-07-05 14:13 -0700 |
| Last post | 2011-07-19 15:20 +0000 |
| Articles | 11 — 7 participants |
Back to article view | Back to comp.lang.c++
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
| From | mrc2323@cox.net (Mike Copeland) |
|---|---|
| Date | 2011-07-05 14:13 -0700 |
| Subject | STL 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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-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]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2011-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]
| From | Stephen Howe <stephen.howe@kantarmedia.com> |
|---|---|
| Date | 2011-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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-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]
| From | Stephen Howe <stephen.howe@kantarmedia.com> |
|---|---|
| Date | 2011-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]
| From | Leigh Johnston <leigh@i42.co.uk> |
|---|---|
| Date | 2011-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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-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]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2011-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]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-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]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2011-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