Interesting Copy Constructors!!

Discussion in 'C++' started by vj, Oct 27, 2005.

  1. vj

    vj Guest

    Hi! I recently came across this intresting behaviour shown by Visual
    C++ 6.0 compiler regarding Copy Constructors. Please tell me that is
    this the standard behaviour shown by all compilers or its limited only
    to VC++.


    Listing 1
    ==================
    #include <iostream>
    using namespace std;
    class Class1
    {
    int i;
    public:
    Class1(int ii)
    {i=ii;cout<<"Class1::parameteized Constructor called with
    "<<ii<<endl;}

    int geti(){return i;}

    Class1(Class1 & c)
    {i=c.i;cout<<"Class1::Copy Constructor called with "<<i<<endl;}


    };

    ostream & operator<<(ostream & os,Class1 & c)
    {return os<<c.geti();}

    Class1 getNext(Class1 c)
    {Class1 cc(c.geti()+1);
    return cc;
    }

    void main()
    {Class1 c(0);
    cout<<getNext(c);
    cin.get();
    }

    Output
    ===============
    Class1::parameteized Constructor called with 0
    Class1::Copy Constructor called with 0
    Class1::parameteized Constructor called with 1
    Class1::Copy Constructor called with 1
    1


    Listing 2
    ===============
    /* same class but diffrent get getNext & main functions*/
    Class1 getNext(Class1 c)
    {return Class1(c.geti()+1);}

    void main()
    {cout<<getNext(Class1(0));
    cin.get();
    }

    output
    ================
    Class1::parameteized Constructor called with 0
    Class1::parameteized Constructor called with 1 //!!Strange No Copy
    Constructor
    1



    It seems that the compiler is bypassing the copy constructor when
    creating a temporary object. It does seems sense as there no need to
    call the copy constructor as the object is already created and
    gauranteed to be unmodified, So it passes the object itself to the
    function.

    However I am not sure that this behaviour a standard behaviour of copy
    constructors?


    Thanks,
    VJ
    vj, Oct 27, 2005
    #1
    1. Advertising

  2. vj

    Zara Guest

    On 26 Oct 2005 20:37:31 -0700, "vj" <> wrote:

    >
    >Hi! I recently came across this intresting behaviour shown by Visual
    >C++ 6.0 compiler regarding Copy Constructors. Please tell me that is
    >this the standard behaviour shown by all compilers or its limited only
    >to VC++.
    >
    >
    >Listing 1
    >==================
    >#include <iostream>
    >using namespace std;
    >class Class1
    >{
    >int i;
    >public:
    > Class1(int ii)
    > {i=ii;cout<<"Class1::parameteized Constructor called with
    >"<<ii<<endl;}
    >
    > int geti(){return i;}
    >
    > Class1(Class1 & c)
    > {i=c.i;cout<<"Class1::Copy Constructor called with "<<i<<endl;}
    >
    >
    >};
    >
    >ostream & operator<<(ostream & os,Class1 & c)
    > {return os<<c.geti();}
    >
    >Class1 getNext(Class1 c)
    > {Class1 cc(c.geti()+1);
    > return cc;
    > }
    >
    >void main()
    >{Class1 c(0);
    > cout<<getNext(c);
    > cin.get();
    >}
    >
    >Output
    >===============
    >Class1::parameteized Constructor called with 0
    >Class1::Copy Constructor called with 0
    >Class1::parameteized Constructor called with 1
    >Class1::Copy Constructor called with 1
    >1
    >
    >
    >Listing 2
    >===============
    >/* same class but diffrent get getNext & main functions*/
    >Class1 getNext(Class1 c)
    > {return Class1(c.geti()+1);}
    >
    >void main()
    >{cout<<getNext(Class1(0));
    > cin.get();
    >}
    >
    >output
    >================
    >Class1::parameteized Constructor called with 0
    >Class1::parameteized Constructor called with 1 //!!Strange No Copy
    >Constructor
    >1
    >
    >
    >
    >It seems that the compiler is bypassing the copy constructor when
    >creating a temporary object. It does seems sense as there no need to
    >call the copy constructor as the object is already created and
    >gauranteed to be unmodified, So it passes the object itself to the
    >function.
    >
    >However I am not sure that this behaviour a standard behaviour of copy
    >constructors?
    >
    >
    >Thanks,
    >VJ


    It is an opional optimization, and it is compiler dependent. Some
    compilers may have optimized the first case to be exactly the same as
    your second case.
    Zara, Oct 27, 2005
    #2
    1. Advertising

  3. vj

    Peter_Julian Guest

    "vj" <> wrote in message
    news:...
    |
    | Hi! I recently came across this intresting behaviour shown by Visual
    | C++ 6.0 compiler regarding Copy Constructors. Please tell me that is
    | this the standard behaviour shown by all compilers or its limited only
    | to VC++.

    Allow me to focus on your class design instead...

    |
    |
    | Listing 1
    | ==================
    | #include <iostream>
    | using namespace std;
    | class Class1
    | {
    | int i;
    | public:
    | Class1(int ii)
    | {i=ii;cout<<"Class1::parameteized Constructor called with
    | "<<ii<<endl;}
    |
    | int geti(){return i;}

    int geti() const
    {
    return i;
    }

    see section 18.10 in the faq
    http://www.parashift.com/c -faq-lite/const-correctness.html

    |
    | Class1(Class1 & c)

    Class1(const Class1& c)

    | {i=c.i;cout<<"Class1::Copy Constructor called with "<<i<<endl;}
    |

    friend std::eek:stream& operator<<(std::eek:stream& os, const Class1& c);

    |
    | };
    |
    | ostream & operator<<(ostream & os,Class1 & c)

    std::eek:stream& operator<<(std::eek:stream& os, const Class1& c)
    {
    os << c.i;
    return os;
    }

    gee, all of a sudden, you don't even need geti()

    | {return os<<c.geti();}
    |
    | Class1 getNext(Class1 c)
    | {Class1 cc(c.geti()+1);
    | return cc;
    | }

    What if getNext(..) attempts to "get" a Class1 node that doesn't exist?
    The creator of the class is responsible to supply the appropriate
    robustness to cover that eventuality. This should not be left to the
    user of the class.

    You'ld have a more robust design if you relied on an STL container to
    store the instances of Class1 and iterators to get next valid elements.
    With iterators, one past the last element in either direction will
    evaluate to null. This greatly simplifies your class's design (and
    eventually: a container's design).

    ie (not tested):

    // test.cpp
    #include "Class1.h" // without geti() or getNext(...)
    #include <iostream>
    #include <ostream>
    #include <list> // or vector, queue, deque

    int main()
    {
    std::list< Class1 > clist;
    clist.push_back(0);
    clist.push_back(1);
    clist.push_back(2);

    // std::copy would be useful here, but for the sake of
    // explaining iterators and their benefits...

    typedef std::list< Class1 >::iterator CIter;
    CIter c_iter = clist.begin(); // where *c_iter is now the first
    element

    // the for loop remains unchanged regardless of clist's actual size
    !
    for( c_iter; c_iter != clist.end(); ++c_iter)
    {
    std::cout << *c_iter << " ";
    }
    std::endl;
    }

    <snip>
    Peter_Julian, Oct 27, 2005
    #3
  4. > However I am not sure that this behaviour a standard behaviour of copy
    > constructors?

    Yes, it is. It is standard.

    --
    Michael Kochetkov
    Michael Kochetkov, Oct 27, 2005
    #4
  5. vj

    vj Guest

    Dear friends,

    Thanks for your support, but i think that there is wierd scenario here.
    On one side Zara says that this is not a standard but mearly an
    optional optimization . However Michael Kochetkov says that it is the
    standard behaviour. Please don't let me confused.... What i really need
    is a definite answer.

    Thanks,
    VJ
    vj, Oct 27, 2005
    #5
  6. vj

    Greg Guest

    Peter_Julian wrote:
    ...
    >
    > You'ld have a more robust design if you relied on an STL container to
    > store the instances of Class1 and iterators to get next valid elements.
    > With iterators, one past the last element in either direction will
    > evaluate to null. This greatly simplifies your class's design (and
    > eventually: a container's design).



    > ie (not tested):
    >
    > // test.cpp
    > #include "Class1.h" // without geti() or getNext(...)
    > #include <iostream>
    > #include <ostream>
    > #include <list> // or vector, queue, deque
    >
    > int main()
    > {
    > std::list< Class1 > clist;
    > clist.push_back(0);
    > clist.push_back(1);
    > clist.push_back(2);
    >
    > // std::copy would be useful here, but for the sake of
    > // explaining iterators and their benefits...
    >
    > typedef std::list< Class1 >::iterator CIter;
    > CIter c_iter = clist.begin(); // where *c_iter is now the first
    > element
    >
    > // the for loop remains unchanged regardless of clist's actual size
    > !
    > for( c_iter; c_iter != clist.end(); ++c_iter)
    > {
    > std::cout << *c_iter << " ";
    > }
    > std::endl;
    > }


    An iterator advanced to the end of a sequence is not guaranteed (or
    even be likely) to evaluate to NULL. Such an iterator cannot even be
    safely dereferenced. It can be compared to another iterator in the same
    container, usually the end() iterator as the example provided
    demonstrates.

    Greg
    Greg, Oct 27, 2005
    #6
  7. vj

    Kai-Uwe Bux Guest

    vj wrote:

    > Dear friends,
    >
    > Thanks for your support, but i think that there is wierd scenario here.
    > On one side Zara says that this is not a standard but mearly an
    > optional optimization . However Michael Kochetkov says that it is the
    > standard behaviour. Please don't let me confused.... What i really need
    > is a definite answer.


    The standard *allows* elimination of copy constructors in certain
    circumstances but it does not *require* the copy constructor to be bypassed
    in these case. Thus, the behavior you observed is blessed but not enforced
    by the standard. The reason that the standard allows elimination of copy
    constructors in some cases is indeed to ease optimization.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Oct 27, 2005
    #7
  8. > Dear friends,
    >
    > Thanks for your support, but i think that there is wierd scenario
    > here. On one side Zara says that this is not a standard but mearly an
    > optional optimization . However Michael Kochetkov says that it is the
    > standard behaviour. Please don't let me confused.... What i really
    > need is a definite answer.

    In addition to the answer above: though a compiler can eliminate objects
    copying during, for example, return value optimization the publicly available
    copy constructor (explicitly or implicitly declared) is a must in this case.
    Even if it is never called at all.

    --
    Michael Kochetkov
    Michael Kochetkov, Oct 27, 2005
    #8
    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. Dave Rudolf
    Replies:
    12
    Views:
    8,251
    Martijn Lievaart
    Feb 6, 2004
  2. Jeremy Smith
    Replies:
    2
    Views:
    574
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    584
    Ron Natalie
    Jun 7, 2007
  4. Peng Yu
    Replies:
    5
    Views:
    385
    Juha Nieminen
    Sep 19, 2008
  5. srp113
    Replies:
    3
    Views:
    457
Loading...

Share This Page