ngo@tammy.harvard.edu (Tom Ngo) (03/22/91)
Twenty days ago, Reid Ellis <rae@utcs.toronto.edu> wrote:
rae> Tom Ngo <ngo@tammy.harvard.edu> writes:
rae> [Are there any ways to accomplish what casting away const does,
rae> without doing so explicitly?]
rae>
rae> How about this?
rae>
rae> struct foo {
rae> foo();
rae> int sometimes() const;
rae> int nonconst();
rae> private:
rae> foo & fRef;
rae> };
rae>
rae> foo::foo() : fRef(*this) {}
rae>
rae> Then, if say "sometimes()" needs to do a non-const thing, it can
rae> simply say "fRef.nonconst()".
rae>
rae> I guess this is essentially casting the const away, but the compiler
rae> won't make a peep about it.
Interesting! This must be a violation of ARM 8.4.3 [References],
which states:
A reference to a plain T can be initialized only with a plain T.
Assuming this rule is intended to apply to the initialization of a
reference in a constructor, it seems you have uncovered an issue that
really ought to be addressed in the ARM: what is that status of a
constructor with regard to constness? Should it be made possible, as
suggested by Jim Adcock <jimad@microsoft.UUCP>, for constructors to be
specified as const? If so, how would a const constructor be permitted
to change data members?
When a const object is constructed, I suppose *this is considered
non-const until the constructor is done. This provides a window of
opportunity to initialize a non-const pointer or reference that is
durable, i.e. will still be alive after the constructor is done.
Perhaps the ARM needs to specify explicit rules regarding the
initialization of such durable entities. Clearly one should not be
able to initialize a non-const pointer or reference from this. But
what about components of this? Can someone come up with a concise
rule that covers all of the ways that the constness of an object might
be subverted by assignments to non-const pointers and references
during construction?
--
Tom Ngo
ngo@harvard.harvard.edu
617/495-1768 lab number, leave message
vaughan@puma.cad.mcc.com (Paul Vaughan) (03/25/91)
From: ngo@tammy.harvard.edu (Tom Ngo) Twenty days ago, Reid Ellis <rae@utcs.toronto.edu> wrote: rae> Tom Ngo <ngo@tammy.harvard.edu> writes: rae> [Are there any ways to accomplish what casting away const does, rae> without doing so explicitly?] rae> rae> How about this? rae> rae> struct foo { rae> foo(); rae> int sometimes() const; rae> int nonconst(); rae> private: rae> foo & fRef; rae> }; rae> rae> foo::foo() : fRef(*this) {} rae> rae> Then, if say "sometimes()" needs to do a non-const thing, it can rae> simply say "fRef.nonconst()". rae> rae> I guess this is essentially casting the const away, but the compiler rae> won't make a peep about it. Interesting! This must be a violation of ARM 8.4.3 [References], which states: A reference to a plain T can be initialized only with a plain T. Assuming this rule is intended to apply to the initialization of a reference in a constructor, it seems you have uncovered an issue that really ought to be addressed in the ARM: what is that status of a constructor with regard to constness? Should it be made possible, as suggested by Jim Adcock <jimad@microsoft.UUCP>, for constructors to be specified as const? If so, how would a const constructor be permitted to change data members? Note that "const" in this context is a property of a pointer, not of an object. For instance class Foo { public: void bar() const; void nonconst(); }; Foo* global; void Foo::bar() const { global->nonconst(); } main() { global = new Foo(); const Foo* f = global; f->bar(); } It doesn't really make any difference that one example uses a global and the other one uses a member. The point is, when the pointer (or reference) was initialized, it was initialized with a non-const. When you realize that the Foo object isn't intrinsically const, you see that nothing is really subverted, and no rules are violated. Also note that the only way you can have intrinsically const objects (that is, ones that might be stored in read only memory) is if they have no constructor. -- Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639 Box 200195, Austin, TX 78720 | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan ---------------------------------------------------------------------------------- I spent from $3 to $10 today to pay interest on the national debt. How about you? ----------------------------------------------------------------------------------
Reid Ellis <rae@utcs.toronto.edu> (04/01/91)
Tom Ngo <ngo@tammy.harvard.edu> writes: >Interesting! This must be a violation of ARM 8.4.3 [References], >which states: > > A reference to a plain T can be initialized only with a plain T. > >Assuming this rule is intended to apply to the initialization of a >reference in a constructor, it seems you have uncovered an issue that >really ought to be addressed in the ARM: what is that status of a >constructor with regard to constness? Should it be made possible, as >suggested by Jim Adcock <jimad@microsoft.UUCP>, for constructors to be >specified as const? If so, how would a const constructor be permitted >to change data members? I think rather than enforcing const-ness at constructor time [after all, a reference to "this" is a completely valid use of a reference, especially if the reference is a reference to a base type] it might have to be done at method time. However, only the link phase has all the information necessary to resolve the reference [a special flag for "reference to *this!" or something] and then notice the reference being used in a non-const way inside a const method. Note that special attention would have to be paid to the afore-mentioned constructors that use references to base classes. e.g.: struct base { int i; }; struct derived : base { derived(); base &b; }; derived::derived() : b(*this) {} Since 'b' is a reference to a base, its address may not == this, especially of derived were multiply inherited. Thus, the linker cannot simply check the address of the reference for equality with "this". Perhaps it might check to see if it is a reference to something "inside the current object" which would include not only "this", but any fancy stuff like references to "int"s inside the class. Reid -- Reid Ellis 1 Trefan Street Apt. E, Toronto ON, M5A 3A9 rae@utcs.toronto.edu || rae%alias@csri.toronto.edu CDA0610@applelink.apple.com || +1 416 362 9181 [work]