Re: Copy ctor and pass-by-value
Dariusz Bismor ha scritto:
Hi all,
I've already posted it on comp.lang.c++, but I've got
little feedback and I (kindly) desire more knowledge.
The code is:
<slighly unreadable code snipped>
please indent your code with spaces, not tabs, when posting...
What bothers me most is the "fun" function, using pass-by-value. According
to ISO, "a function can change the values of its non-const parameters, but
these changes cannot affect the values of the arguments except where a
parameter is of a reference type". My copy constructor does not guarantee
not to change the "model" parameter, in fact it does change it.
Surprisingly, gcc v.4.1.1 (Linux Mandriva) allows this code to compile
(and
work). The copy ctor changes the value of "k" member of "inst1" object and
compiler does not care.
Surprisingly? What does surprise you? I don't understand. A function is
called, that function have side-effects, you see the side-effects.
What's wrong with that? Consider this:
void f(int& i) { i = 1; }
int main()
{
int i = 0;
f(i);
std::cout << i << "\n"; // prints 1, not 0
}
What should have surprised you is that, in your particular case, you
*may not* see the side-effects, and the compiler would still be
producing the correct result. Weird, isn't it? That's because the
compiler *may* (but it's not obliged to) optimize away the call to the
copy constructor even if it has side-effects.
After the answer on comp.lang.c++ I begin to understand why uncomenting
the
line with second function call (using return-by-value) causes compiler to
throw:
error: no matching function for call to 'X::X(X)'
note: candidates are: X::X(X&)
Anyway, I'll be glad on more explanation on what compiler means
by the above message.
The compiler doesn't "throw". It's just producing the correct diagnostic
for an ill-formed program. It's only your application that may "throw"
(when you use a throw-expression).
The error message is in fact quite clear, once you understand what's
behind it. The return value of a function is always an rvalue, that is:
not an lvalue. For a definition of both terms, see ?3.10 in the standard
or just google for them. An rvalue cannot be bound to a non-const
reference, in this example: a rvalue of type X can't be bound to a X&.
It might be bound to an X or a const X&, but not an X&. Unfortunately
the only candidate function available takes a X& so there's no match.
You may ask: shouldn't the compiler generate implicitly a copy
constructor that takes a const X&? The answer is no, because X::X(X&) is
itself a copy constructor and if at least one copy constructor is
explicitly provided, the compiler won't generate another copy
constructor implicitly.
I've also tried it with Borland Builder 6: it does not even warn in both
cases, and the code compiles OK.
(Of course, changing the copy constructor and adding "const" in parameter
list solves the problem.)
BB6 is clearly not implementing rvalue binding properly, such behavior
is not compliant to the standard.
HTH,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]