copy constructor - optimized away or not?

Discussion in 'C++' started by Alexander Stippler, Oct 30, 2005.

  1. The following code snippet (those of you who read my last postings
    might be familiar with it ;-)):

    //--------------------------------------------------------------------
    template<class Impl>
    class Vector {};

    template<class Ref>
    class VectorView: public Vector<VectorView<Ref> >
    {
    Ref r;
    public:
    VectorView() {}
    operator const Ref &() const { return r; }
    operator Ref &() { return r; }
    };

    template<class T>
    class DenseVector: public Vector<DenseVector<T> >
    {
    public:
    DenseVector() {}

    DenseVector(const DenseVector<T> &rhs) {}

    VectorView<DenseVector<T> >
    operator()(int from, int to)
    { return VectorView<DenseVector<T> >(); }
    };

    int fun(const DenseVector<double> &x) { return 1; }

    int main()
    {
    DenseVector<double> x, y;
    DenseVector<double> &w = x(1,3); // (1)
    DenseVector<double> z = x(1,3); // (2)
    fun(x(1,3)); // (3)
    return 0;
    }
    //--------------------------------------------------------------------

    What we are not able to comprehend is what happens in the three marked
    lines:
    In (2) x(1,3) creates an object of type VectorView<...> and its member
    r is actually copied into z.
    In (1) and (3) no such copying takes place.
    Perhaps someone could tell us in detail what's going on internally in
    those lines. Does it have to to with the copy constructor optimization
    allowed by the standard in 12.8(15).
    And if yes why does e.g. gcc 4.0 treat the three cases differently?
    The standard does not enforce this optimization. But can it be
    guaranteed that in (1) and (3) there will be no copying and that there
    will always be copying in (2)?

    Thanks
    Alex
    Alexander Stippler, Oct 30, 2005
    #1
    1. Advertising

  2. Alexander Stippler wrote:
    > int main()
    > {
    > DenseVector<double> x, y;
    > DenseVector<double> &w = x(1,3); // (1)
    > DenseVector<double> z = x(1,3); // (2)
    > fun(x(1,3)); // (3)
    > return 0;
    > }
    > //--------------------------------------------------------------------
    >
    > What we are not able to comprehend is what happens in the three marked
    > lines:
    > In (2) x(1,3) creates an object of type VectorView<...> and its member
    > r is actually copied into z.
    > In (1) and (3) no such copying takes place.


    In (1) you explicitly ask the compiler not to copy anything. `w` is a reference.

    In (2) the compiler is allowed to optimise away the copy. I guess g++ was confused by the
    fact that the type you return is different from the type you copy to.

    In (3) you pass the new object to "fun" by reference, so again you explicitly ask it not
    to copy.

    You would understand your own code better if you had a simple example without all these
    templates which only obscure the real problem.

    --

    Valentin Samko - http://www.valentinsamko.com
    Valentin Samko, Oct 30, 2005
    #2
    1. Advertising

  3. In <4364f239$0$11871$> Valentin
    Samko wrote:
    > Alexander Stippler wrote:
    >> int main()
    >> {
    >> DenseVector<double> x, y;
    >> DenseVector<double> &w = x(1,3); // (1)
    >> DenseVector<double> z = x(1,3); // (2)
    >> fun(x(1,3)); // (3)
    >> return 0;
    >> }
    >> //--------------------------------------------------------------------
    >>
    >> What we are not able to comprehend is what happens in the three
    >> marked lines: In (2) x(1,3) creates an object of type VectorView<...>
    >> and its member r is actually copied into z. In (1) and (3) no such
    >> copying takes place.

    >
    > In (1) you explicitly ask the compiler not to copy anything. `w` is a
    > reference.
    >
    > In (2) the compiler is allowed to optimise away the copy. I guess g++
    > was confused by the fact that the type you return is different from
    > the type you copy to.
    >
    > In (3) you pass the new object to "fun" by reference, so again you
    > explicitly ask it not to copy.
    >


    But in (2) I pass the object by reference too. No difference to (3)
    with respect to this.

    > You would understand your own code better if you had a simple example
    > without all these templates which only obscure the real problem.
    >


    Template code has different behavior in several areas. So I do not
    want to understand it for non-template code and then recognize that
    template code behaves diffent. And the templates do not add complexity
    here. And in one place in the code they are not superfluous, but
    essential to realize the Barton-Nackman-Trick.

    > --
    >
    > Valentin Samko - http://www.valentinsamko.com
    >
    Alexander Stippler, Oct 30, 2005
    #3
  4. In <43653c2b$0$50353$> Valentin
    Samko wrote:
    > Alexander Stippler wrote:
    >>>> DenseVector<double> x, y;
    >>>> DenseVector<double> &w = x(1,3); // (1)
    >>>> DenseVector<double> z = x(1,3); // (2)
    >>>> fun(x(1,3)); // (3)

    >
    >>> In (2) the compiler is allowed to optimise away the copy. I guess
    >>> g++ was confused by the fact that the type you return is different
    >>> from the type you copy to.
    >>>
    >>> In (3) you pass the new object to "fun" by reference, so again you
    >>> explicitly ask it not to copy.
    >>>

    >>
    >> But in (2) I pass the object by reference too. No difference to (3)
    >> with respect to this.

    > I do not see any references in the (2) code path. What do you mean by
    > "I pass the object by reference too"?
    >


    The signature of fun is void fun(const DenseVector<double> &x), so
    the argument is a const &. And the copy constructor for (2) expects
    a const & too. Where am I wrong?
    Alexander Stippler, Oct 30, 2005
    #4
  5. Alexander Stippler wrote:
    >>> DenseVector<double> x, y;
    >>> DenseVector<double> &w = x(1,3); // (1)
    >>> DenseVector<double> z = x(1,3); // (2)
    >>> fun(x(1,3)); // (3)


    >> In (2) the compiler is allowed to optimise away the copy. I guess g++
    >> was confused by the fact that the type you return is different from
    >> the type you copy to.
    >>
    >> In (3) you pass the new object to "fun" by reference, so again you
    >> explicitly ask it not to copy.
    >>

    >
    > But in (2) I pass the object by reference too. No difference to (3)
    > with respect to this.

    I do not see any references in the (2) code path. What do you mean by "I pass the object
    by reference too"?

    --

    Valentin Samko - http://www.valentinsamko.com
    Valentin Samko, Oct 30, 2005
    #5
  6. Alexander Stippler wrote:
    >>>>> DenseVector<double> x, y;
    >>>>> DenseVector<double> &w = x(1,3); // (1)
    >>>>> DenseVector<double> z = x(1,3); // (2)
    >>>>> fun(x(1,3)); // (3)
    >>>> In (2) the compiler is allowed to optimise away the copy. I guess
    >>>> g++ was confused by the fact that the type you return is different
    >>>> from the type you copy to.
    >>>>
    >>>> In (3) you pass the new object to "fun" by reference, so again you
    >>>> explicitly ask it not to copy.
    >>>>
    >>> But in (2) I pass the object by reference too. No difference to (3)
    >>> with respect to this.

    >> I do not see any references in the (2) code path. What do you mean by
    >> "I pass the object by reference too"?
    >>

    > The signature of fun is void fun(const DenseVector<double> &x), so
    > the argument is a const &. And the copy constructor for (2) expects
    > a const & too. Where am I wrong?


    1. Yes, you have a reference in the copy constructor, I missed that.

    2. operator() returns object by value, this leads to one temporary (which may be optimised
    away, this depends on implementation of operator ()).

    3. this has nothing to do with the function "fun" as it is not called in (2).

    4. In addition to a possible temporary, you are creating a new object "z" which will
    contain a copy of that temporary.

    --

    Valentin Samko - http://val.samko.info
    Valentin Samko, Oct 30, 2005
    #6
    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. William Payne
    Replies:
    4
    Views:
    497
    Karthiik Kumar
    Aug 28, 2004
  2. Markus Dehmann
    Replies:
    11
    Views:
    758
    Pete Becker
    Mar 20, 2005
  3. Markus Henschel
    Replies:
    8
    Views:
    652
    benben
    Feb 14, 2006
  4. Jonathan Lee

    Are destructors ever optimized away?

    Jonathan Lee, May 13, 2009, in forum: C++
    Replies:
    10
    Views:
    689
  5. cinsk
    Replies:
    35
    Views:
    2,593
    James Kanze
    Oct 11, 2010
Loading...

Share This Page