Topic: const and aggregates (long)
Author: jason@cygnus.com (Jason Merrill)
Date: Sat, 30 Apr 1994 00:24:06 GMT Raw View
>>>>> Alan Rooks <alan@vedge.com> writes:
> All the compilers that I've tried take this (all of these at file scope)
> const int i; // error: no initializer
> to be an error. But this
> int i;
> is equivalent to
> int i = 0;
> so why isn't the above error line equivalent to
> const int i = 0;
> ??
I think that this has something to do with C++'s abandonment of
maybe-external variables from C. In C, both definitions without
initializers go into the common segment, and are merged with other possible
definitions in other modules. In C++, the const is defined with file
scope, while the non-const is defined with global scope. It makes sense to
leave the non-const variable alone at startup and modify it later, but it
doesn't make much sense to special-case a constant that happens to be zero.
On the other hand, this does break uniformity, so I'd agree with you that
it's a pretty worthless change.
Jason
Author: alan@vedge.com (Alan Rooks)
Date: Sat, 23 Apr 1994 21:12:05 GMT Raw View
I've been looking at the issue of putting const objects or references
in classes and unions, and how it affects whether they are aggregates.
(ARM 8.4.1, Jan '94 WP 8.5.1 -- this will hereafter be called "the WP").
To start -- the meaning of const doesn't seem to be nailed down too
carefully, or consistently (as far as I can tell; please correct me if
I'm wrong). The ARM says that objects with const types must be initialized.
In the case of built-in types, this seems to mean "with an explicit
initializer".
All the compilers that I've tried take this (all of these at file scope)
const int i; // error: no initializer
to be an error. But this
int i;
is equivalent to
int i = 0;
so why isn't the above error line equivalent to
const int i = 0;
??
If I have a class X with a default constructor, then
X x;
is equivalent to
X x = X();
(except that the latter could involve a copy of a temporary).
All of the compilers I've tried take
const X x;
to be equivalent to
const X x = X();
so they have no problem with "const X x;" at all. Why this inconsistency?
Note that some compilers will allow "const X x;" even when there's no
constructor at all, since the generated default constructor gets used.
Some compilers won't allow this, though.
----------------------------------------------------------------------------
Now this type
struct s {
const int i;
};
is an aggregate according to ARM 8.4.1, so it shouldn't require a constructor
(since s::i can be initialized with a brace-enclosed list), even though
ARM 12.6.2 says that a constructor with a ctor-initializer is the only way
to initialize s::i. This statement in the ARM seems to be the reason that
several compilers (cfront and bcc, at least) give an error for this type
("you must define a constructor"). This statement has been fixed in the WP
section 12.6.2.
Is it a requirement that, if struct s has constructors, then the definition
of every one of them must have a ctor-initializer for field "const int i"?
All of the compilers seem to take this as a requirement, but I don't see it
written down anywhere.
----------------------------------------------------------------------------
Now, what about unions? A union can't have base classes or virtual
functions, so it is an aggregate as long as it doesn't have private or
protected members, or constructors. But there are some cases where it
seems hard to initialize a union which is an aggregate, with a brace-
enclosed list. This is okay:
union u {
const int i;
double d;
};
but what about this (where the const field is not the first)?
union u {
double d;
const int i;
};
The const is not the first element of the union, so the const can't be
initialized by a brace-enclosed list.
Most compilers (if they can handle a union with a const member and no
constructors without erroneously complaining) seem to think this union
is okay, as long as objects of type union u are initialized with a
brace-enclosed list.
----------------------------------------------------------------------------
And what about anonymous unions? There's another whole can of worms.
union {
const int i;
const double d;
};
The members i and d can be accessed as part of the enclosing scope, but
are they also in the enclosing scope in the sense that if this union is
part of a struct (or class), i and/or d must be initializable (by brace-
enclosed list or constructor ctor-initializer)? It's obviously meaningless
to initialize *both* i and d. Example:
struct s {
union {
const int i;
const double d;
};
};
Both i and d are "in the scope" of s, but they obviously can't both be
initialized, so what are the rules about brace-enclosed initializers for
a struct s, or what are the rules for which ctor-initializers must appear
in definitions of constructors for s?
----------------------------------------------------------------------------
Finally, what if I declare the anonymous union to be const, instead of
its members?
struct s {
const union {
int i;
double d;
};
};
It's not clear (at least to me) whether a const anonymous union is even
allowed.
----------------------------------------------------------------------------
All of these points seem to apply to reference members of classes, structs,
and unions, too, except the first point (explicit versus implicit
initialization of const objects; there is no implicit initialization
of references).
Can anyone provide any enlightenment on these points? Is the X3J16/WG21
committee aware of these difficulties?
Thanks,
Alan Rooks
--
Alan Rooks Visual Edge Software, St-Laurent (Montreal)
alan@vedge.com or alan%vedge.uucp@iros1.iro.umontreal.ca