Topic: A C++ asymmetry


Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/14
Raw View
Siemel B. Naran wrote:

> Now if C++ were designed from scratch, without regard for C, then I
> think it would not have compiler generated default constructors.
> Allan went even further -- he said that it we should not even have
> compiler generated copy constructors.

Strange: I have a rule to never write these special member
functions myself (of course, there are exceptions to this
rule).

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Aldo Aleardi <aldo.a@interplanet.it>
Date: 1999/09/15
Raw View
On 13 Sep 1999 16:17:07 GMT, Francis Glassborow
<francis@robinton.demon.co.uk> wrote:

[sorry for snipping]
>However it seems difficult to imagine a case where a user written copy
>ctor was needed but a compiler generated default ctor would do the right
>thing.  Would you like to provide a counter example?  Without one it
>seems that the standard is entirely correct in this asymmetry.
>

Maybe my mathematical background raises its head from time to time,
so allow me to put it this way:

(ISO C++ compiler speaks)
"Hey user, you have defined no copy constructor for your class
so, whether or not you have defined some constructors, I'm willing
to generate a default copy constructor for you! You know well
the way it will behave, don't 'you? Come on then, if it satisfies
your needs, use it; otherwise handle your object's copy construction
by yourself."

This is right, isn't it? It's up to the user to choose.

Now, if in this correct sentence I replace the "copy constr.."
occurences with "constr.." and viceversa, I get a wrong sentence
according to the standard. And that seems a bit illogical to me.

Back to the point!

class MyClass {
public:
//
//
private:
//
//
 MyClass( const MyClass& ); // not implemented
};

Let's suppose for a moment that for this particular class
the most appropriate constructor, say for efficiency reasons,
be the implicitly default generated constructor: what to do
in such situation?
A very simple workaround would be to add a line of code
to MyClass:

class MyClass {
public:
  MyClass(){}
  //...
};

but a little later
...
MyClass mca[1000];
...
Yes I know, I have implicitly defined MyClass::MyClass() inline,
but I have no guarantee that it, no matter how simple it is,
will be actually inlined so I have to take into account the
legendary Murphy's Law.  There will surely be 1000 "calls" of
MyClass::MyClass()  with the subsequent runtime overhead.

My conclusions (probably wrong)? This asymmetry should be
eliminated by making the sentence above correct or not with
or without the replacements I have pointed out.


>Francis Glassborow      Journal Editor, Association of C & C++ Users
>64 Southfield Rd
>Oxford OX4 1PA          +44(0)1865 246490

Best Regards, Aldo
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/16
Raw View
On 15 Sep 99 13:06:19 GMT, Aldo Aleardi <aldo.a@interplanet.it> wrote:

: Maybe my mathematical background raises its head from time to time,
: so allow me to put it this way:

Nice logic.  Consider:

I.   Thow shalt have a copy constructor.
II.  Thow shalt have a destructor.
III. Thow shalt have a copy assignment operator.
IV.  Thow shalt not declare any one of these without declaring all of
     them.

Dispensation: You may define a virtual destructor with an empty body
without declaring the other two.

Enforcement I-III: If you don't declare them, they will be declared
and if a need arises they will be defined.

Enforcement IV: Great hords of code gremlins will descend upon your
executable; however, you do have free will.

Benevolence: If you do not associate with unfaithful constructors,
the gift of eternal default constructor will be bestowed upon you.

Taken in good faith, there is clearly no asymmetry.

Do you see the light?

;-)
John


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: postmast.root.admi.gov@iname.com (blargg)
Date: 1999/09/13
Raw View
In article <yfHaNyPjoGWxa6bbbTdKITIXiWzP@4ax.com>, Aldo Aleardi
<aldo.a@interplanet.it> wrote:

[code examples snipped from message]

> I would like to understand the reasons why the following asymmetry,
> in my opinion of course, is allowed by the standard.

As most asymmetries, this one is likely an artifact of the fact that the
language is designed for practicality over theoretical elegance. It is
about doing, not admiring.

> If I define a default constructor and no copy constructor, the
> standard says that a default copy constructor is implicitly defined,
> so this code is well-formed
...
> but if I define a default copy constructor and no default constructor
> the standard says that a default constructor will not be implicitly
> defined, so the following code will not compile:
> I do not understand this behavior:

Surely you do, as you just explained it clearly.

> after all the state of a default
> constructed object could be modified by the member functions
> so that the copy of an object would make sense etc. etc...
> Just out of curiosity.

If you need to define a copy constructor, it is very likely you also need
a default constructor to establish the invariant for a newly-created
object. Can you think of situations where this wouldn't be the case?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/13
Raw View
On 12 Sep 1999 14:53:59 GMT, Aldo Aleardi <aldo.a@interplanet.it> wrote:

>If I define a default constructor and no copy constructor, the
>standard says that a default copy constructor is implicitly defined,
>so this code is well-formed

>but if I define a default copy constructor and no default constructor
>the standard says that a default constructor will not be implicitly
>defined, so the following code will not compile:

Here is a guess.

Most objects need a copy constructor, so one is implicitly defined.
The implicit constructor usually does the right thing -- ie, applies
the copy constructor for each of the sub-objects.

A default constructor should never be implicitly generated, but for
backward compatibility with C -- ie, a struct is basically a class
with all members public -- the compiler will create one.  Example,
given "struct S { std::vector<int> v; int i; };" the compiler
creates a S::S().

--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/13
Raw View
In article <yfHaNyPjoGWxa6bbbTdKITIXiWzP@4ax.com>, Aldo Aleardi
<aldo.a@interplanet.it> writes
>I do not understand this behavior: after all the state of a default
>constructed object could be modified by the member functions
>so that the copy of an object would make sense etc. etc...
>Just out of curiosity.

Actually  it took me several years to even realise that a default copy
ctor did inhibit compiler generation of a default ctor.

Actually you are thinking of copy ctors (there are possibly four of
them) and other ctors as being disjoint sets.  This is not the case as a
copy ctor can be produced by defaulting 2nd and subsequent parameters
for a ctor whose first parameter is a reference to a, possibly cv
qualified, instance of the class.

The actual rule is simple.  A compiler generated default ctor is only
available if no ctors have been provided.

Now it is not unreasonable that a class has a non-copy ctor provided
when the compiler generated copy ctor would be entirely safe and do
exactly what you expect (and possibly do so more efficiently than a
programmer can write - as the compiler knows what the copy ctor does it
can optimise very aggressively)

However it seems difficult to imagine a case where a user written copy
ctor was needed but a compiler generated default ctor would do the right
thing.  Would you like to provide a counter example?  Without one it
seems that the standard is entirely correct in this asymmetry.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/13
Raw View

Aldo Aleardi wrote:
>
> I would like to understand the reasons why the following asymmetry,
> in my opinion of course, is allowed by the standard.
>
> If I define a default constructor and no copy constructor, the
> standard says that a default copy constructor is implicitly defined,

>
> but if I define a default copy constructor and no default constructor
> the standard says that a default constructor will not be implicitly
> defined

It makes a little more sense if you state the rule as it appears
in the language definition:

1.  A default constructor will be implicitly generated if no contructor
    is defined.

2.  A copy constructor will be implicitly generated if no copy constructor
    is defined.

The definition of any kind of constructor inhibits the implicit generation
of the default.  The purpose is that some classes are designed such that
the *MUST* be initialized with a non-default constructor so you don't want
to compiler to chuck in a implicitly generated.  It might have been nice
to either make an exception for the copy constructor, or to also inhibit
the copy constructor in this case, but I think it was found that in most
cases the behavior as specified fits the most common situations.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW <allan_w@my-deja.com>
Date: 1999/09/14
Raw View
In article <37DD1C53.4DAF6B25@sensor.com>,
  Ron Natalie <ron@sensor.com> wrote:

> ... It might have been nice to either make an exception for
> the copy constructor, or to also inhibit the copy constructor
> in this case, but I think it was found that in most
> cases the behavior as specified fits the most common
> situations.

I disagree. I have found that the automatically-created
copy constructor is one of the biggest sources of errors.

Beginning programmers don't know that the compiler does
this; every month or two someone posts a question to
comp.std.c++ asking why his constructor fires twice but
the destructor fires three times (for instance, when
returning an object by value) and we have to explain copy
constructors to him.

More experienced programmers simply forget to define the
copy constructor, or else they add a second parameter
and forget to supply a default value. Once again, the
compiler's "helpful" version steps in.

In my opinion, the way that the rule should have worked is,
if the programmer doesn't provide any constructors then the
compiler will. But if the programmer defines even one
constructor, then there are no implicit ones.

...not that I expect this rule to change during my lifetime...

--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/14
Raw View
AllanW wrote:
>
> Beginning programmers don't know that the compiler does
> this; every month or two someone posts a question to
> comp.std.c++ asking why his constructor fires twice but
> the destructor fires three times (for instance, when
> returning an object by value) and we have to explain copy
> constructors to him.

Is this really a big issue?  We'd have to explain to him
why his code doesn't compile if it weren't.

>
> More experienced programmers simply forget to define the
> copy constructor, or else they add a second parameter
> and forget to supply a default value. Once again, the
> compiler's "helpful" version steps in.

This argument, I'll go with.  I would be happy if providing
any constructor disables both the default and the copy constructor.

Of course we might have to continue and disable the copy assingment
operator as well...

It would be nice however, if you are going to do this, if there
were some way to get the behavior that the implicitly generated
ones do in the user provided one.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Daniel M. Pfeffer" <pfefferd@nospam.internet-zahav.net>
Date: 1999/09/14
Raw View
Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
news:slrn7tnubc.7vt.sbnaran@localhost.localdomain...
> On 12 Sep 1999 14:53:59 GMT, Aldo Aleardi <aldo.a@interplanet.it> wrote:
>

[snip]

> A default constructor should never be implicitly generated, but for
> backward compatibility with C -- ie, a struct is basically a class
> with all members public -- the compiler will create one.  Example,
> given "struct S { std::vector<int> v; int i; };" the compiler
> creates a S::S().

By your argument, a default constructor should only be created for PODs
(i.e. non-derived structs with no virtual methods or destructors). Why is it
created for classes, or _any_ struct without non-default constructors?

I suspect that the true reason was either orthogonality or removal of the
confusion caused by yet another exception to the rule.

--
Daniel Pfeffer
--------------
Remove 'nospam' from my address in order to contact me directly
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Andrew R. Thomas-Cramer" <artc@prism-cs.com>
Date: 1999/09/14
Raw View
1. Compatibility with C.
   One of C++'s goals is backwards compatibility with C. ANSI C structs
implicitly support copy and assignment, even if someone's written one or
more initialization functions for the struct. The present rule thus makes
classes behave similarly to C structs.

2. Parallelism
   If copy constructors were created implicitly only if _no_ other
constructors were defined,  either the assignment operator would either need
to follow the same rule, or not. If it did, defining a single constructor
explicitly would turn off the implicit assignment operator, which seems an
unnatural dependency. If it didn't, it would not satisfy parallelism with
the copy constructor, and a particular class could have an implicit
assignment operator but not an implicit copy constructor.

3. Utility
  Mr. Glassborow covered this in a previous article.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/14
Raw View
On 14 Sep 99 15:58:54 GMT, Daniel M. Pfeffer
>Siemel B. Naran <sbnaran@uiuc.edu> wrote in message

>> A default constructor should never be implicitly generated, but for
>> backward compatibility with C -- ie, a struct is basically a class
>> with all members public -- the compiler will create one.  Example,
>> given "struct S { std::vector<int> v; int i; };" the compiler
>> creates a S::S().

>By your argument, a default constructor should only be created for PODs
>(i.e. non-derived structs with no virtual methods or destructors). Why is it
>created for classes, or _any_ struct without non-default constructors?

No, my argument says nothing of POD.  I see no high-level distinction
between POD and non-POD types.  The rule I'd like is for a default
constructor to never be generated, no matter what.

However, because we'd like the C code "struct S { int i; char c; };"
to work in C++, we have the backward compatibility rule: if you don't
define any constructors, the compiler defines a default constructor.
Similarly the C++ code "struct S { std::vector<int> v; int i; };"
should be as much like the C code as possible, and thus it will
have a compiler generated S::S() as well.

Now if C++ were designed from scratch, without regard for C, then I
think it would not have compiler generated default constructors.
Allan went even further -- he said that it we should not even have
compiler generated copy constructors.


>I suspect that the true reason was either orthogonality or removal of the
>confusion caused by yet another exception to the rule.

--
--------------
siemel b naran
--------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/14
Raw View
On 14 Sep 99 10:36:31 GMT, AllanW <allan_w@my-deja.com> wrote:

>Beginning programmers don't know that the compiler does
>this; every month or two someone posts a question to
>comp.std.c++ asking why his constructor fires twice but
>the destructor fires three times (for instance, when
>returning an object by value) and we have to explain copy
>constructors to him.

But once they understand the issues behind the compiler
generated copy constructor (what is is, where it is used),
is it worth it?  I think yes, because the copy constructor
is most useful.


>More experienced programmers simply forget to define the
>copy constructor, or else they add a second parameter
>and forget to supply a default value. Once again, the
>compiler's "helpful" version steps in.

And what about when we write a templated copy constructor
but forget to write the normal copy constructor?

   template <class T>
   struct S { template <class U> S(const S<U>&); };
   int main() { S<int> s1; S<int> s2(s1); }

The "S<int> s2(s1)" calls the compiler generated
S<T>::S(const S<T>&), and not the templated version!



>In my opinion, the way that the rule should have worked is,
>if the programmer doesn't provide any constructors then the
>compiler will. But if the programmer defines even one
>constructor, then there are no implicit ones.
>
>...not that I expect this rule to change during my lifetime...

Well if we could do this or something like this

   struct S {
      S() { }
      S::S(const S&) default { }
   };

then I'd have to agree with you.  I like this idea of yours
especially because

 - I get to explicitly say that I want a copy constructor
 - I get to specify the access level (ie: private, protected, public)

Similar remarks must apply for the operator=.

And while we're at it, the one-arg constructor should be explicit
by default.

--
--------------
siemel b naran
--------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Aldo Aleardi <aldo.a@interplanet.it>
Date: 1999/09/12
Raw View
I would like to understand the reasons why the following asymmetry,
in my opinion of course, is allowed by the standard.

If I define a default constructor and no copy constructor, the
standard says that a default copy constructor is implicitly defined,
so this code is well-formed

#include <iostream>
#include <string>
using namespace std; // only for less typing

class MyClass {
public:
    MyClass( const string& s = string() ) : m_s ( s )
    {
         cout << "MyClass::MyClass( const string& )" << endl;
    }
    ~MyClass()
    {
         cout << "MyClass::~MyClass()" << endl;
    }
   // member functions....
private:
   string m_s;
};

int main()
{
    MyClass mc1( "myclass" );
    MyClass mc2(  mc1 );
    return 0;
}

/****************** output ************************
MyClass::MyClass( const string& ) //   mc1
MyClass::~MyClass()                        // ~mc2
MyClass::~MyClass()                        // ~mc1
***************************************************/

but if I define a default copy constructor and no default constructor
the standard says that a default constructor will not be implicitly
defined, so the following code will not compile:

// same as above

class MyClass {
public:
    MyClass( const MyClass& rhs ) : m_s ( rhs.m_s )
    {
         cout << "MyClass::MyClass( const MyClass& )" << endl;
    }
   // same as above
};

int main()
{
    MyClass mc1;             // line 2
    MyClass mc2(  mc1 );
    return 0;
}
/*****************************output*******************************
 In function `int main()':
 line 2: no matching function for call to `MyClass::MyClass ()'
*********************************************************************/

I do not understand this behavior: after all the state of a default
constructed object could be modified by the member functions
so that the copy of an object would make sense etc. etc...
Just out of curiosity.

TIA, aldo



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]