Topic: When do members of const objects become const?


Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/10/17
Raw View
Given

struct T
{
  int i;
  T();
  ~T();
};

static const T x;

I'm sure that the above works (is well defined) with
  T::T():i(5){}

I'm less sure that it works with
  T::T(){ i = 5; }

If I use the second version of the constructor the lifetime of x.i would
seem to begin before the body of the constructor is entered.  Is the
assignment in the second constructor assigning to a const int?

In the ARM the wording said that every non-static data member of a const
object was const.  In CD2 it uses another wording, that it is illegal to
modify (auto and static) const objects (with the exception of mutable
members) during their lifetimes.  Since x is not yet alive during the body
of T::T(), it may be ok to modify x.

The meaning seems to have gone from
  since x is const, x.i is const.
to
  since x is const, you can't modify x.i during the lifetime of x.

As Valentin Bonnard pointed out to me offline, this means optimizers often
can't optimize references to members of const objects:

void f()
{
  cout << x.i;
  h();
  cout << x.i; // Can compiler assume value of x.i hasn't changed?
};

int* pi;

T::T():i(1)
{
  pi = &i;
  f();
};

void h(){ *pi = 2; } // Invalidates a possible optimization in f().

There might also be a question of if it is legal to perform the
lvalue to rvalue conversion of x.i in
  cout << x.i;
when x is in the process of being constructed.  Since i has been
initialized (even though x is not yet alive) this looks like it is well
defined.

So I believe the example is valid, but it is close enough to the edge that
I'm not sure.  Any pointers?

Also, I assume that if it is ok to modify x.i during the body of T::T() it
is also ok to modify it during the body of T::~T().  Is that correct?

The example above also points out a small hole in the type system.
  const T z;
  *pi = 7; // Assignment to z.i is illegal even though no cast was
involved.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/18
Raw View
"Bill Wade" <bill.wade@stoner.com> writes:

 >Given
 >
 >struct T
 >{
 >  int i;
 >  T();
 >  ~T();
 >};
 >
 >static const T x;
 >
 >I'm sure that the above works (is well defined) with
 >  T::T():i(5){}
 >
 >I'm less sure that it works with
 >  T::T(){ i = 5; }

It is well defined in both cases.

 >If I use the second version of the constructor the lifetime of x.i would
 >seem to begin before the body of the constructor is entered.  Is the
 >assignment in the second constructor assigning to a const int?
 >
 >In the ARM the wording said that every non-static data member of a const
 >object was const.  In CD2 it uses another wording, that it is illegal to
 >modify (auto and static) const objects (with the exception of mutable
 >members) during their lifetimes.  Since x is not yet alive during the body
 >of T::T(), it may be ok to modify x.

Correct.

 >The meaning seems to have gone from
 >  since x is const, x.i is const.
 >to
 >  since x is const, you can't modify x.i during the lifetime of x.

Yes, this was deliberate.  A const object does not become const until
the end of its constructor.

 >As Valentin Bonnard pointed out to me offline, this means optimizers often
 >can't optimize references to members of const objects:
 >
 >void f()
 >{
 >  cout << x.i;
 >  h();
 >  cout << x.i; // Can compiler assume value of x.i hasn't changed?
 >};
 >
 >int* pi;
 >
 >T::T():i(1)
 >{
 >  pi = &i;
 >  f();
 >};
 >
 >void h(){ *pi = 2; } // Invalidates a possible optimization in f().
 >
 >There might also be a question of if it is legal to perform the
 >lvalue to rvalue conversion of x.i in
 >  cout << x.i;
 >when x is in the process of being constructed.  Since i has been
 >initialized (even though x is not yet alive) this looks like it is well
 >defined.

This is OK, because the constuctor for x has already begun at that point.
See 12.7[class.cdtor] paragraph 1.

 >Also, I assume that if it is ok to modify x.i during the body of T::T() it
 >is also ok to modify it during the body of T::~T().  Is that correct?

Yes.

 >The example above also points out a small hole in the type system.
 >  const T z;
 >  *pi = 7; // Assignment to z.i is illegal even though no cast was
 >involved.

Yes, the committee is well aware of that hole, and it has been
mentioned here on comp.std.c++ several times, I think.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]