copy constructor - optimized away or not?

A

Alexander Stippler

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
 
V

Valentin Samko

Alexander said:
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.
 
A

Alexander Stippler

In said:
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.
 
A

Alexander Stippler

In said:
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?
 
V

Valentin Samko

Alexander said:
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"?
 
V

Valentin Samko

Alexander said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top