I have the following class definition:
class test2{
public:
int y;
test2(int ui) : y(ui){}
test2(const test2& t) : y(5){}
test2& operator= (const test2& t){ y = 6; return *this; }
};
In an expression like
test2 t2(test2(20)); or
test2(t2) = test2(20);
neither the copy-constructor nor the assgnment operator get executed.
t2 end up with y=20.
But in the following case the copy constructor gets called:
test2 t = test2(20);
test2 t2(t); // or test2 t2 = t;
Can someone explain to me what's going on there?
Most likely optimisation of some kind. The compiler is allowed to
create code that would omit the use of the copy-constructor (and to
construct the object directly) in certain cases, even if the copy c-tor
has side effects. The fact that the copy c-tor actually is supposed to
produce a different object than what you end up having, looks like a bug
to me. However, whose bug it is is rather debatable. When you write a
copy constructor and instead creating a unique element that has really
nothing in common with the object of which it's supposed to be a copy,
then it could be construed as *your* bug, and you're just reaping what
you've sown.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
My example code above was not supposed to be "useful". I had some
problems with statements of that kind in some more complex
environment. So I constructed these examples to see what method was
called... In my opinion statements should have a well defined behavior
regardless of whether the code is useful or not. And I would like to
understand why that code behaves in this way.
I understand. Again, the compiler is allowed not to create a copy (i.e.
allowed not to invoke the copy constructor) in certain situations.
Constructing a function return value is one of those cases. Defining an
object is another. You've run into this. That behaviour is consistent
with what the Standard says.
Tried this out and got the same results. A friend referenced the
following from the standard:
12.2 Temporary objects [class.temporary]
1 Temporaries of class type are created in various contexts: binding
an rvalue to a reference (8.5.3), returning
an rvalue (6.6.3), a conversion that creates an rvalue (4.1, 5.2.9,
5.2.11, 5.4), throwing an exception (15.1),
entering a handler (15.3), and in some initializations (8.5). [Note:
the lifetime of exception objects is
described in 15.1. ] Even when the creation of the temporary object is
avoided (12.8), all the semantic
restrictions must be respected as if the temporary object was created.
[Example: even if the copy constructor
is not called, all the semantic restrictions, such as accessibility
(clause 11), shall be satisfied. ]
2 [Example:
class X {
// ...
public:
// ...
X(int);
X(const X&);
~X();
};
X f(X);
void g()
{
X a(1);
X b = f(X(2));
a = f(a);
}
Here, an implementation might use a temporary in which to construct X
(2) before passing it to f() using
X’s copyconstructor;
alternatively, X(2) might be constructed in the space used to hold the
argument.
Also, a temporary might be used to hold the result of f(X(2)) before
copying it to b using X’s copyconstructor;
alternatively, f()’s result might be constructed in b. On the other
hand, the expression
a=f(a) requires a temporary for either the argument a or the result of
f(a) to avoid undesired aliasing of
a. ]
Tom M.
thx, that clarifies the issue :)
K. H.