By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,952 Members | 1,732 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,952 IT Pros & Developers. It's quick & easy.

three times copy ctor called, one ctor called, why?

P: n/a
#include <iostream>
#include <string>
#include <map>
using namespace std ;
class tst
{
public :
tst() { cout << "tst::constructor" << endl ; }
tst(const tst & that) { cout << "tst::copy constructor" << endl ;
}
tst & operator =( const tst & that ) { cout << "tst::operator ="
<< endl ; }

~tst() { cout << "tst::destructor" << endl ; }
} ;
int main()
{
map < string , tst > a ;
tst e ;
a.insert(pair < string , tst > ("standard",e) ) ;

system("pause") ;
return 0 ;
}
///// Output ////////////
tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor
Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Apricot wrote:
#include <iostream>
#include <string>
#include <map>
using namespace std ;
class tst
{
public :
tst() { cout << "tst::constructor" << endl ; }
tst(const tst & that) { cout << "tst::copy constructor" << endl ;
}
tst & operator =( const tst & that ) { cout << "tst::operator ="
<< endl ; }
Why have you not returned anything from this function?

~tst() { cout << "tst::destructor" << endl ; }
} ;
int main()
{
map < string , tst > a ;
tst e ;
a.insert(pair < string , tst > ("standard",e) ) ;
Actually, that should be 'const string'. I think it should be OK this
way, but I seem to recall some implementations having trouble inserting
into a map this way, or by using make_pair. For that reason, using
map<>::value_type (which you can be sure has exactly the right type) may
be preferable. I'd probably do this:

typedef map<string, tst> MapType;
MapType a;
tst e;
a.insert(MapType::value_type("standard", e));

system("pause") ;
return 0 ;
}
///// Output ////////////
tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor


I don't see these results. What I do see might shed some light, however:

tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor
pause: not found
tst::destructor
tst::destructor

Notice that the ill-fated "pause" command came before two of the
destructor calls. Perhaps your pausing is preventing you from seeing
some of the destructor calls. If not that, then I suspect your compiler
is broken and due for an update.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.
Jul 22 '05 #2

P: n/a
You are expecting a single copy ctor, because e is passed to a.insert.
but it should be called one more time - ("standard", e) to pair <T1,
T2> conversion. now why it is being called third time probably is due
to internal pair implementation (object is copied somewhere in temp
object) ?

Amit Manocha

Apricot <yi**@21cn.com> wrote in message news:<cb********************************@4ax.com>. ..
#include <iostream>
#include <string>
#include <map>
using namespace std ;
class tst
{
public :
tst() { cout << "tst::constructor" << endl ; }
tst(const tst & that) { cout << "tst::copy constructor" << endl ;
}
tst & operator =( const tst & that ) { cout << "tst::operator ="
<< endl ; }

~tst() { cout << "tst::destructor" << endl ; }
} ;
int main()
{
map < string , tst > a ;
tst e ;
a.insert(pair < string , tst > ("standard",e) ) ;

system("pause") ;
return 0 ;
}
///// Output ////////////
tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor

Jul 22 '05 #3

P: n/a
Kevin Goodsell <us*********************@neverbox.com> wrote in message news:<TW******************@newsread2.news.pas.eart hlink.net>...
Apricot wrote:
#include <iostream>
#include <string>
#include <map>
using namespace std ;
class tst
{
public :
tst() { cout << "tst::constructor" << endl ; }
tst(const tst & that) { cout << "tst::copy constructor" << endl ;
}
tst & operator =( const tst & that ) { cout << "tst::operator ="
<< endl ; }

~tst() { cout << "tst::destructor" << endl ; }
} ;
int main()
{
map < string , tst > a ;
tst e ;
a.insert(pair < string , tst > ("standard",e) ) ;

system("pause") ;
return 0 ;
}
///// Output ////////////
tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor


I don't see these results. What I do see might shed some light, however:

tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor
pause: not found
tst::destructor
tst::destructor

Notice that the ill-fated "pause" command came before two of the
destructor calls. Perhaps your pausing is preventing you from seeing
some of the destructor calls. If not that, then I suspect your compiler
is broken and due for an update.


Sorry for the long quote, but isn't this obvious? e is destroyed after
the pause, and the single tst in a is also destroyed later.

Regards,
Michiel Salters
Jul 22 '05 #4

P: n/a
Apricot <yi**@21cn.com> wrote in message news:<cb********************************@4ax.com>. ..
#include <iostream>
#include <string>
#include <map>
using namespace std ;
class tst
{
public :
tst() { cout << "tst::constructor" << endl ; }
tst(const tst & that) { cout << "tst::copy constructor" << endl ;
}
tst & operator =( const tst & that ) { cout << "tst::operator ="
<< endl ; }

~tst() { cout << "tst::destructor" << endl ; }
} ;
int main()
{
map < string , tst > a ;
tst e ;
a.insert(pair < string , tst > ("standard",e) ) ;

system("pause") ;
return 0 ;
}
///// Output //////////// tst::constructor
tst::copy constructor
tst::copy constructor
tst::copy constructor
tst::destructor
tst::destructor


From what I understand all the STL containers get populated by
copying. This means that the only time the constructor gets called is
when you do
tst e;
a.insert(pair < string , tst > ("standard",e) );
First you create a (temporary) pair which gets populated by copying
("standard", e) into it.

In the second step the internal workings of the map implementation you
seem to be using creates a pair for internal use (2nd temporary in
this case) by copying ("standard", e) from the first pair into it.

Finally at the third step the map creates a node in the binary tree
that is populated by copying the 2nd temporary pair into it. (Note: it
is not required that any implementation uses a binary tree to store
map data, it just happens that all the implementations I know do it
that way)

fourth step is destroying the 2nd temporary pair (as seen by your
tst::destructor output), the one created by the insert action

fifth step is destroying the first temporary pair, the one you
explicitly created.
Hopefully the next bit of code can make it a bit clearer. replace your
main with it (it should also give you two more destructor calls).
Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3. {
  4. map < string , tst > a;
  5. cout << "map created\n" ;
  6. tst e ;
  7. cout << "tst e created\n" ;
  8. std::pair<string, tst> mep("standard", e);
  9. cout << "pair created\n";
  10. a.insert(mep) ;
  11. }
  12.  
  13. cout << "mash keyboard to continue" << endl;
  14. cin.get();
  15. return 0 ;
  16. }
  17.  
Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.