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

Discussion in 'C++' started by Apricot, Apr 15, 2004.

  1. Apricot

    Apricot Guest

    #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::eek:perator ="
    << 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
    Apricot, Apr 15, 2004
    #1
    1. Advertising

  2. 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::eek:perator ="
    > << 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.
    Kevin Goodsell, Apr 15, 2004
    #2
    1. Advertising

  3. Apricot

    Amit Manocha Guest

    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 <> wrote in message news:<>...
    > #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::eek:perator ="
    > << 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
    Amit Manocha, Apr 15, 2004
    #3
  4. Kevin Goodsell <> wrote in message news:<TWqfc.11306$>...
    > 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::eek:perator ="
    > > << 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
    Michiel Salters, Apr 15, 2004
    #4
  5. Apricot

    velthuijsen Guest

    Apricot <> wrote in message news:<>...
    > #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::eek:perator ="
    > << 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).
    Code:
    int main()
    {
    {
    map < string , tst > a;
    cout << "map created\n" ;
    tst e ;
    cout << "tst e created\n" ;
    std::pair<string, tst> mep("standard", e);
    cout << "pair created\n";
    a.insert(mep) ;
    }
    
    cout << "mash keyboard to continue" << endl;
    cin.get();
    return 0 ;
    }
    
    velthuijsen, Apr 16, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. djskrill
    Replies:
    9
    Views:
    684
    djskrill
    Oct 1, 2003
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,675
    Smokey Grindel
    Dec 2, 2006
  3. NVH
    Replies:
    8
    Views:
    473
    mlimber
    Jul 6, 2006
  4. , India

    copy ctor vs default ctor

    , India, Aug 15, 2007, in forum: C++
    Replies:
    2
    Views:
    394
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=
    Aug 15, 2007
  5. puzzlecracker
    Replies:
    8
    Views:
    411
    James Kanze
    Apr 15, 2008
Loading...

Share This Page