Topic: Initialization ambiguities
Author: jimc@julia.math.ucla.edu
Date: 10 Apr 91 19:02:11 GMT Raw View
Two possible ambiguities about initialization in Ellis & Stroustrup,
"The Annotated C++ Reference Manual". First, suppose class A is an
aggregate (sect 8.4.1) containing one data member, an array of V's,
which are also aggregates.
struct V { float data[2]; }
struct A { V array[2]; }
A wrong = { {1, 2}, {3, 4} }; //{3,4} inits 2nd data member
//which does not exist
V v0 = {1, 2};
V v1 = {3, 4};
A ambig = { { v0, v1 } }; //What does v0 init?
//Could be ambig.array[0], could be ambig.array[0].data[0]
When an aggregate is initialized from a list of aggregates, and when one
of these matches a sub-aggregate, is it copied or does it (disastrously)
initialize members of the sub-aggregate? The book can be read either way.
What I really wanted was the effect shown above as "wrong", just as a
traditional "C" array would be initialized.
Second ambiguity: a derived class has a constructor from a reference to its
base class. Is this a copy constructor? Specifically:
struct Base {
Base(args); //No explicit copy constructor here
};
struct Derv : public Base {
Derv(const Base& b); //Pseudo-copy constructor
};
Derv& invert(const Base& b) {
Derv result(b);
/* thrash about */
return result; //Using which copy constructor?
}
Reading in sect. 12.6.1 "Explicit Initialization" p. 288: "...function
return is equivalent to Derv dest = result". p. 284: "This value is
used as the argument to a copy constructor". Sect. 5.3.3 "New" p. 61:
"Access and ambiguity control are done for both operator new() and the
constructor". It all implies very strongly that a constructor should be
sought that will swallow a Derv, which the provided constructor will
do. Nonetheless my compiler demanded an exact match on argument type,
chucked my constructor, and generated a bitwise copy (whereupon on
destruction a free pointer was freed again, the heap was smeared,
MS-DOS was smeared, my disc was smeared, and matters went downhill from
there. Fortunately I make backups.)
An authoritative statement would be appreciated in the evolving standard
of whether a copy constructor can have non-exact matching arguments.
If you post a reply, I would appreciate a mailed copy since my news machine
has a very short expiration time.
James F. Carter (213) 825-2897
UCLA-Mathnet; 6221 MSA; 405 Hilgard Ave.; Los Angeles, CA, USA 90024-1555
Internet: jimc@math.ucla.edu BITNET: jimc%math.ucla.edu@INTERBIT
UUCP:...!{ucsd,ames,ncar,gatech,purdue,rutgers,decvax,uunet}!math.ucla.edu!jimc
James F. Carter (213) 825-2897
UCLA-Mathnet; 6221 MSA; 405 Hilgard Ave.; Los Angeles, CA, USA 90024-1555
Internet: jimc@math.ucla.edu BITNET: jimc%math.ucla.edu@INTERBIT
UUCP:...!{ucsd,ames,ncar,gatech,purdue,rutgers,decvax,uunet}!math.ucla.edu!jimc
Author: jimad@microsoft.UUCP (Jim ADCOCK)
Date: 19 Apr 91 17:42:42 GMT Raw View
In article <1991Apr10.190211.29678@math.ucla.edu> jimc@MATH.UCLA.EDU (Jim Carter) writes:
|Second ambiguity: a derived class has a constructor from a reference to its
|base class. Is this a copy constructor? Specifically....
....my compiler demanded an exact match on argument type,
|chucked my constructor, and generated a bitwise copy....
I agree that ARM is less than 100% clear in its language on this issue,
but it seems to me the intent is pretty darned clear. All the examples
given show copy constructors [and assignments] of a class X matching
an X& or a const X&. For example, see ARM page 296 "If a class X has
any X::operator=() that takes an argument of class X, the default assignment
will not be generated. I believe the authors [and most readers] didn't
recognize that there is a [slight] ambiguity in the text. I think the
[almost] universally recognized intent is that a copy constructor must have
some kind of Dirv& parm, not a Base& parm. If then, a programmer doesn't
explicitly lay down a copy constructor [or assignment op] [that is: one that
takes a Dirv& or const Dirv& parm] then a compiler must lay down a default
*memberwise* constructor [or assignment op.] Which presumably is what
bit you.
Because of these kinds of problems, many old time C++ hacks just by habit
manually create copy constructors and assignment operators for each class
they create. Otherwise it is easy to make changes to a class which defeats
the default constructors and assignments -- and one doesn't notice the
problem since one hasn't explicitly laid down code for the constructor and
assignment. [Also, this [IMHO] good habit of "always" explicitly laying down
constructors and assignment were reinforced by the flaky code generating
capabilities of many early C++ compilers]
In summary: I agree that the ARM is less than 100% clear on this issue,
but I don't think there is any "emerging consensus" on the issue -- rather
I think its been clear for several years that copy constructors and assignment
require a parm of Dirv& or const Dirv&, that the generated copy constructors
and assignment work by *memberwise* assignment, not *bitwise* assignment,
and this is universally accepted in all recent compiler releases.
Perhaps the committee can make a point of cleaning up these slight ambiguities
in the ARM text?