Topic: What is a copy constructor?


Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 1995/05/09
Raw View
The draft C++ standard working paper states that a copy constructor
for a class X must be of the form: X(X&) or X(const X&), possibly
with additional defaulted arguments, and a default copy constructor
(preferably X(const X&)) will be generated if no user-define copy
constructor is supplied.

This will invalidate code like the sample below. Is this intentional?

// Please excuse typos
class X
{
  public:
  int i;
  X(int j=0) : i(j){}
  X(volatile X& x) : i(x.i) {}  // NOT a copy constructor
};  // No copy constructor so compiler generates X(const X&)

void f()
{
  X a;
  X b = a;  // ERROR - ambiguous X(cvonst X&) or X(volatile X&)
}


The current C++ compiler I tried accepts X(volatile X&) as a copy
constructor, but this is contrary to the draft. An appendix states
that not having volatile copy constructors was an intentional
decision, but was this effect intended?





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/05/09
Raw View
In article c6l@fsgm01.fnal.gov, b91926@fsgm01.fnal.gov (David Sachs) writes:
>The draft C++ standard working paper states that a copy constructor
>for a class X must be of the form: X(X&) or X(const X&), possibly
>with additional defaulted arguments, and a default copy constructor
>(preferably X(const X&)) will be generated if no user-define copy
>constructor is supplied.
>
>This will invalidate code like the sample below. Is this intentional?

Disallowing X(volatile X&) as a copy ctor was intentional, but not for
the purpose of breaking existing code. The ARM was vague on exactly
what constituted a copy ctor and under what circumstances the compiler
should generate one. The draft standard clarifies that issue. You could
expect to find different existing compilers making different choices.
Future compilers should all agree.

>
>// Please excuse typos
>class X
>{
>  public:
>  int i;
>  X(int j=0) : i(j){}
>  X(volatile X& x) : i(x.i) {}  // NOT a copy constructor
>};  // No copy constructor so compiler generates X(const X&)
>
>void f()
>{
>  X a;
>  X b = a;  // ERROR - ambiguous X(cvonst X&) or X(volatile X&)
>}

Right. If you provide neither X(X&) nor X(const X&), the compiler will
generate X(const X&). You provide a non-const, non-volatile X as a parameter,
and the result is an ambiguity. If you want to handle volatile objects
specially, you have to provide one or both of the other copy ctors as well,
to prevent ambiguities when you have both volatile and non-volatile objects.

You can view this a breaking your program, but the program might not
have compiled anyway, depending on the compiler.
---
Steve Clamage, stephen.clamage@eng.sun.com







Author: chase@centerline.com (David Chase)
Date: 1995/05/09
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:
|> ... but the program might not
|> have compiled anyway, depending on the compiler.

But since this is true of legal programs as well, what conclusions
can we draw from this? :-)

speaking for myself,

David Chase





Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 1995/05/10
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

>In article c6l@fsgm01.fnal.gov, b91926@fsgm01.fnal.gov (David Sachs) writes:
>>The draft C++ standard working paper states that a copy constructor
>>for a class X must be of the form: X(X&) or X(const X&), possibly
>>with additional defaulted arguments, and a default copy constructor
>>(preferably X(const X&)) will be generated if no user-define copy
>>constructor is supplied.
>>
>>This will invalidate code like the sample below. Is this intentional?

>Disallowing X(volatile X&) as a copy ctor was intentional, but not for
>the purpose of breaking existing code. The ARM was vague on exactly
>what constituted a copy ctor and under what circumstances the compiler
>should generate one. The draft standard clarifies that issue. You could
>expect to find different existing compilers making different choices.
>Future compilers should all agree.

>>
>>// Please excuse typos
>>class X
>>{
>>  public:
>>  int i;
>>  X(int j=0) : i(j){}
>>  X(volatile X& x) : i(x.i) {}  // NOT a copy constructor
>>};  // No copy constructor so compiler generates X(const X&)
>>
>>void f()
>>{
>>  X a;
>>  X b = a;  // ERROR - ambiguous X(cvonst X&) or X(volatile X&)
>>}

>Right. If you provide neither X(X&) nor X(const X&), the compiler will
>generate X(const X&). You provide a non-const, non-volatile X as a parameter,
>and the result is an ambiguity. If you want to handle volatile objects
>specially, you have to provide one or both of the other copy ctors as well,
>to prevent ambiguities when you have both volatile and non-volatile objects.

>You can view this a breaking your program, but the program might not
>have compiled anyway, depending on the compiler.
>---
>Steve Clamage, stephen.clamage@eng.sun.com

********************


I hope that the final standard STRONGLY emphasizes the point that
X(volatile X&) and X(const volatile X&) are NOT copy constructors,
as well as the corresponding situation with operator=.

I have seen code that relies on the behavior of some current compilers,
and uses X(const volatile X&) with a non-trivial body.