Topic: const Constructors


Author: Michael Haggerty <mhagger@green.physics.wm.edu>
Date: 1997/06/15
Raw View
Perhaps what is needed is a way to say that a pointer or reference
points to something constant if and only if it is a member of a
constant object; this would be something like the opposite of mutable,
which says that a member is non-constant even if it is a member of a
constant object.

The new keyword should probably be `constable' :-)

E.g., the earlier example would become

  struct foo {
      int value:
      constable int& target;
      foo(int v, constable int& t): value(v), target(t) {}
      };

  int a_value = 0;
  int a_target = 0;
  const foo a_foo(a_value, a_target); // legal

  int const c_target = 1;
  foo b_foo(a_value, c_target); // illegal

  void test() {
      a_foo.value = 1;    // not legal
      a_foo.target = 1;   // newly illegal
      }

Then there would probably be a way to define the concept of a const
constructor (or at least a constable constructor).  In fact,
constructors declared like the `foo' constructor above might be all
that is needed.

`constable' would probably be allowed anywhere that `const' is
normally allowed.

--
Michael Haggerty
mhagger@mail.delos.physics.wm.edu
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/26
Raw View
climate@on.bell.ca (Mike Whiten) writes:

|>    According to g++ you are correct and others have told me that the standard
|>    is as you say it is.  I find this very strange however.  What I'm being told
|>    right now is that references behave differently from all other types in
|>    terms of const consistency with the container:
|>
|>    struct X
|>    {
|>
|>        Y     mem1;
|>        Y*    mem2;
|>        Y&    mem3;
|>    };
|>
|>    What you are telling me is that if I instantiate a "const X" object,
|>    mem1 will be const, mem2 will be const (that is the pointer itself),
|>    but mem3 won't.

Well, if you consider mem3 as a reference, the reference itself will
certainly be constant:-).  I see your point, however.  The const-ness of
the object referred to by the expression .mem1 or .mem2 is that of the X
object, whereas the const-ness of the object referred to be .mem3
depends on the declaration of mem3, and not on the const-ness of the X
object.

I think the best way of looking at it is to think that there is no
(sub-)object mem3; all the declaration X::mem3 does is declare a name
(in the scope of the class X) for another object (which is not
necessarily part of X).  The const-ness of this other object is
independant of the const-ness of X.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/05/28
Raw View
On 24 May 97 09:39:03 GMT, Mike Whiten wrote:

: Paul D. DeRocco (pderocco@strip_these_words.ix.netcom.com) wrote:

: : You and Mike seem to disagree on the interpretation of a non-const
: : reference within a const structure:

: :  struct foo {
: :      int value:
: :      int& target;
: :      foo(int v, int& t): value(v), target(t) {}
: :      };

: :  int a_value = 0;
: :  int a_target = 0;
: :  const foo a_foo(a_value, a_target);

: :  void test() {
: :      a_foo.value = 1; // not legal
: :      a_foo.target = 1; // legal?
: :      }

: : I can't set a_foo.value, because a_foo is const, right? But does the
: : constness of a_foo prevent me from setting a_foo.target, even though it
: : is a non-const reference? That is the question.

: Thank you for getting to the meat of the matter... the issue got confused
: my my poor choice of words.  I apologize for that.

: In response to this question (which is came about in response to my
: proposal for a "const constructor"), here is what 3 compilers say
: about the line:

:   a_foo.target = 1;

:       g++ 2.7.2:   legal
:         HPUX CC:   not-legal
:        HPUX aCC:   not-legal

And here is the answer from the CD2

|  5.2.5  Class member access                                  [expr.ref]
|4 If E2 is declared to have type "reference to  T",  then  E1.E2  is  an
|  lvalue; the type of E1.E2 is T.

In a_foo.target = 1, E1 is a_foo of type foo const and E2 is target of
type int&.  E1.E2 is an lvalue of type int.  The cv qualifiers of E1
do not effect the cv qualifiers of E2.

The assignment is clearly legal.  g++ and my other three compilers get
it right and this is an HPUX bug.

As is explicitely stated in many places in the draft, references act
like pointer consts.

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         ]
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/22
Raw View
climate@on.bell.ca (Mike Whiten) writes:

|>  Just what does "int const&" mean?

Reference to a const int.  You cannot modify the int referred to through
this reference.

|>  I've bound a reference to an r-value
|>  this way before but I always thought I was hacking the compiler doing it --
|>  ie. severely non-portable and certainly non-Standard code.

No.  It is fully standard.  You can bind an rvalue to a reference to a
const.  You cannot bind an rvalue to a reference to a non const.  To
cite the classical example:

 unsigned int        i ;
 int&                ri = i ;      //  Illegal, reference to non-const
    int const&          rci = i ;     //  Legal, reference to const.

Note that in the latter case, the object actually bound is a temporary
initialized with i; the result of the (implicit) conversion from
unsigned to int.

|>  How can the binding between an identifier and an object (ie. a reference)
|>  be const or non-const since there are no operations defined for references.

I don't understand the question.  The "binding" is always const; a
reference must be bound when it is created, and the binding cannot be
changed later.  The const refers to the bound object, or rather, to the
bound object as seen through the reference.

|>  The ARM itself says that references aren't "first-class" types.
|>
|>  Is this standard C++?  This seems to me to be too cute by half.

Very standard, and widely used.  Most of the function arguments in the
standard library are references to const, exactly like this.  (The ARM
and the draft standard generally write it "const int&", instead of "int
const&", but the meaning is the same.)

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/22
Raw View
climate@on.bell.ca (Mike Whiten) writes:

|>  John Potter (jpotter@falcon.lhup.edu) wrote>
|>  >
|>  > >     Given the following class definition:
|>  >
|>  > >         class Child
|>  > >         {
|>  > >              Child( const Parent& m )
|>  > >         : mother( m )  // illegal
|>  > >       { }
|>  >
|>  > >       Child( Parent& m )
|>  > >         : mother( m ) // ok
|>  > >              { }
|>  > >
|>  > >    public:
|>  > >       const Parent&   getMother() const;
|>  > >       Parent&         getMother();
|>  >
|>  > >    private:
|>  > >       Parent&   mother;
|>  >
|>  > >        };
|>  >
|>  > >     The situation I'm facing is I cannot create a Child instance and
|>  > >     bind it to either const *or* non-const Parent objects.   If I type
|>  > >     "mother" as being "const Parent&"'s then the second constructor
|>  > >     fails.
|>  >
|>  > No it doesn't, it is ok to bind a const& to a non-const object.  But
|>  > the second get then requires a cast.
|>
|>  I stand corrected.  I think what I meant to say is I cannot do what I want,
|>  which is to let this constructor initialize the reference mother without
|>  committing to it being const or non-const.  The problem, of course, isn't
|>  the constructor definition, but that the member "mother" is declared const.

You must commit the reference at the point of declaration; the
const-ness is part of the (statically checked) type.

You can bind a non-const object to a reference to const without any
problems.  You can also bind a const object to a non-const reference,
but you'll need a cast to do so, and any attempt to modify the const
object will result in undefined behavior.

If you want the const-ness of Child to somehow depend on the const-ness
of the Mother argument, I don't think it can be done.  To begin with, I
think that providing two constructors:

 Child::Child( Parent& ) ;
 Child::Child( Parent const& ) ;

will result in ambiguity at many of the call sites; if the argument is
non-const (even if it is an rvalue), both constructors will match, and
I'm not sure that the current rules in the draft give one priority.
(This was not very clear in the ARM, and different compilers will handle
the case differently today.)

About the closest you can come is to define two classes:
ChildOfNonConstParent and ChildOfConstParent.  The user must decide
explicitly which to use.  I actually find this preferable.  The choice
will in any case be made at compile time (according to which constructor
the compiler chooses to call), so why not make it explicit (and get an
immediate error if you want ChildOfNonConstParent, but only have a const
Parent handy).

In similar cases (iterators, mostly), I generally derive the
ChildOfNonConstParent from ChildOfConstParent, and also make it a friend
of ChildOfConstParent.  The const functions are in ChildOfConstParent,
as is the actual reference (to a const).  The constructor of
ChildOfConstParent takes a const reference, so there is no problem with
initialization.  The constructor of ChildOfNonConstParent takes a
reference to a non-const, which it passes to the constructor of
ChildOfConstParent (no problem: non-const->const).  The
ChildOfNonConstParent accesses the reference in the base class, and
casts away the const.  This is legal, since it knows that the reference
was in fact initialized by a reference to non-const (the argument to its
constructor).

Done this way, the two classes are tightly coupled, but I still find
this solution preferrable to the alternatives.

|>  > >     What I'd like it to be able to omit the "const" from the data member
|>  > >     declaration (as shown above) and let the instantiation context
|>  > >     determine if they are const references or not.  A const constructor
|>  > >     would allow this:
|>  >
|>  > If a class has a char* member then a const object has a char* const,
|>  > not a char const*.  You are asking to break a lot of programs.  It is
|>  > quite reasonable for a const object to have references/pointers to
|>  > nonconst objects.  The pointer in the const object can not be changed
|>  > but the object to which it points is changable.
|>
|>  As I understand the current state of C++, references and pointers have
|>  completely different behaviour in this context.  When implementing a
|>  relationship with a pointer, one introduces an intermediate object
|>  (the pointer itself) which can be const or non-const.  When implementing
|>  a relationship with a reference, there is no intermediate object
|>  (accessible through the language) to designate as const or non-const.
|>  If, for example, a class has a "char&" member, then a const instance
|>  of that class will have a "const char&" member.

Not at all.  In this sense, references are *always* const.  (When we
speak of a const reference, we really mean a reference to const.)  The
"const" qualifies the refered to object, just as it does with a pointer,
e.g.:

 const int*          pointer to const int
    int const*          pointer to const int
    int *const          const pointer to non-const int, i.e.:
      the pointer cannot be modified, but the int it
      points to can.

For references, replace the '*' with a '&' in the first two above, and
the situation is the same.  The last one would be illegal, since the
const would apply to the reference, and references are not real objects.

If the pointer is a member of a class, and the actual object is const,
then the const-ness of the object corresponds to the last case for the
pointer; the pointer cannot be modified, but the pointed to object can.
Since the const-ness of a reference is irrelevant, the const-ness of the
object in which it is declared has no effect on what can be done with or
through the reference.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/24
Raw View
James Kanze (james-albert.kanze@vx.cit.alcatel.fr) wrote:
: climate@on.bell.ca (Mike Whiten) writes:
: |>
: |>  I stand corrected.  I think what I meant to say is I cannot do what I want,
: |>  which is to let this constructor initialize the reference mother without
: |>  committing to it being const or non-const.  The problem, of course, isn't
: |>  the constructor definition, but that the member "mother" is declared const.

: You must commit the reference at the point of declaration; the
: const-ness is part of the (statically checked) type.

  According to g++ you are correct and others have told me that the standard
  is as you say it is.  I find this very strange however.  What I'm being told
  right now is that references behave differently from all other types in
  terms of const consistency with the container:

  struct X
  {

      Y     mem1;
      Y*    mem2;
      Y&    mem3;
  };

  What you are telling me is that if I instantiate a "const X" object,
  mem1 will be const, mem2 will be const (that is the pointer itself),
  but mem3 won't.

  I accept what everyone is telling me; this is part of the standard.
  It doesn't seem logical to me however.  And it breaks a principle which
  I gleaned from the ARM which says that after initialization, a reference
  is indistinguishable from a non-reference l-value.

  To me this is a needless inconsistency.

  ...And I still think a const constructor makes as much sense as a const
  member function.

Mike
---
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/24
Raw View
James Kanze (james-albert.kanze@vx.cit.alcatel.fr) wrote:
: climate@on.bell.ca (Mike Whiten) writes:

: |>  Just what does "int const&" mean?

: Reference to a const int.  You cannot modify the int referred to through
: this reference.

  I just mis-interpreted this syntax... never seen it before and didn't
  know it was parseable.  Had no idea what it meant.

: |>  How can the binding between an identifier and an object (ie. a reference)
: |>  be const or non-const since there are no operations defined for references.

: I don't understand the question.  The "binding" is always const; a
: reference must be bound when it is created, and the binding cannot be
: changed later.  The const refers to the bound object, or rather, to the
: bound object as seen through the reference.

    The binding is always "constant", not "const".  It doesn't make
    any sense for a binding to be "const".  That was my point.
---
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/24
Raw View
Paul D. DeRocco (pderocco@strip_these_words.ix.netcom.com) wrote:

: You and Mike seem to disagree on the interpretation of a non-const
: reference within a const structure:

:  struct foo {
:      int value:
:      int& target;
:      foo(int v, int& t): value(v), target(t) {}
:      };

:  int a_value = 0;
:  int a_target = 0;
:  const foo a_foo(a_value, a_target);

:  void test() {
:      a_foo.value = 1; // not legal
:      a_foo.target = 1; // legal?
:      }

: I can't set a_foo.value, because a_foo is const, right? But does the
: constness of a_foo prevent me from setting a_foo.target, even though it
: is a non-const reference? That is the question.

Thank you for getting to the meat of the matter... the issue got confused
my my poor choice of words.  I apologize for that.

In response to this question (which is came about in response to my
proposal for a "const constructor"), here is what 3 compilers say
about the line:

  a_foo.target = 1;

      g++ 2.7.2:   legal
        HPUX CC:   not-legal
       HPUX aCC:   not-legal
  MS Visual C++:   OS thought one of my kernel libraries was a WordPerfect
     file and the damn thing won't boot anymore.

I vote for not-legal.  It doesn't seem consistent to the way the rest
of the language (namely the static type system) behaves.  If it *is*
illegal,  then I think we need a "const constructor".

Mike
---
[ 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: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/05/25
Raw View
Mike Whiten wrote:
 class Child
       {
            Child( const Parent& m )
              : mother( m )  // illegal
            { }

            Child( Parent& m )
              : mother( m ) // ok
            { }

         public:
            const Parent&   getMother() const;
            Parent&         getMother();

         private:
            Parent&   mother;

      };
--------------------
I'm not sure I understand the desired functionality, but I think you can
get pretty close using existing language rules:

struct Parent {
 int value;
};

class ConstChild
{
public:
 ConstChild( const Parent& m )
  :mother( const_cast<Parent &>(m) )
 { }
 const Parent&   getMother() const
  { return mother; }

protected:
 Parent&   mother;

};

class Child : public ConstChild {
public:
 Child(Parent &m)
  :ConstChild(m) {}
 Parent &getMother( ) const
  {return mother; }
};


int main ( )
{
 Parent mom;
 mom.value = 7;
 ConstChild eleanor(mom);
 Child samatha(mom);
 samatha.getMother( ).value = 4; //just fine
 //eleanor.getMother( ).value = 4; //illegal
}
---
[ 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: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/05/19
Raw View
On 19 May 97 03:37:54 GMT, Mike Whiten wrote:

: Edmund Robinson (ebrobins@ibl.bm) wrote:
: : To my knowledge const member functions can not modify data members.
: : That means a const constructor would not be able to set the values of the
: : class object.  A const constructor is an oxymoron

: const object can, however, be written to at initialization.  Example:

:  const int        i = 5;        // writes to const object
:  const Complex    c(0.0, 0.0);  // writes to const object

: I don't see any reason to preclude initialization of known const members
: since you can initialize const objects in other contexts.

ok

: I'll briefly summarize why I think this should be allowed:

:    Given the following class definition:

:        class Child
:        {
:             Child( const Parent& m )
:        : mother( m )  // illegal
:      { }

:      Child( Parent& m )
:        : mother( m ) // ok
:             { }
:
:   public:
:      const Parent&   getMother() const;
:      Parent&         getMother();

:   private:
:      Parent&   mother;

:       };

:    The situation I'm facing is I cannot create a Child instance and
:    bind it to either const *or* non-const Parent objects.   If I type
:    "mother" as being "const Parent&"'s then the second constructor fails.

No it doesn't, it is ok to bind a const& to a non-const object.  But
the second get then requires a cast.

:    What I'd like it to be able to omit the "const" from the data member
:    declaration (as shown above) and let the instantiation context
:    determine if they are const references or not.  A const constructor
:    would allow this:

If a class has a char* member then a const object has a char* const,
not a char const*.  You are asking to break a lot of programs.  It is
quite reasonable for a const object to have references/pointers to
nonconst objects.  The pointer in the const object can not be changed
but the object to which it points is changable.

:   Child( const Parent& m )
:     : mother( m ) const
:   { }

The syntax would be
 Child (const Parent& m) const : mother(m) { }

:    since the const implies that "this" is of type "const Child*", the
:    data member, "mother", is const.  The binding of the references is
:    still legal, because one can always initialize const object
:    identifiers.  This constructor would only be invoked when initializing
:    a const Child object.

But that is not how function overloading works.  Example follows.

:    Initialization of the const member would only
:    be allowed in the initializer list.

:    A const constructor allows me to do the following:

:    const Parent     mom1;
:   Parent     mom2;

:           const Child      child1( mom1 );
:    const Child      child2( mom2 );
:   Child      child3( mom2 );

Yep

:  //  Child      child4( mom1 );
:        /* illegal - taking away const'ness */

Nope, it calls the const ctor.

:   child1.getMother();  // calls const mem func
:   child2.getMother();  // calls const mem func
:   child3.getMother();  // calls non-const mem func

Yep, and
 child4.getMother();  // calls non-const mem func

:    Without the const constructor, only child3 could be created.  If I
:    declare "mother" as being a "const Parent&" in the class definition,
:    I can't create any Child from a non-const Parent& (eg child2 and child3).

Sure you can, again.  Here is an example using another member
function.

struct C {
 void f (int const&) const;
 void f (int&);
 };
void foo () {
 int i(5);
 C c;
 C const cc;
 cc.f(i); // int& -> int const& -> f(C const&, int const&)
 cc.f(7); // f(C const&, int const&)
 c.f(i);  // f(C&, int&)
 c.f(7);  // C& -> C const& -> f(C const&, int const&)
 }

You don't like the last one, but that is how it works.  So, let's give
you your const constructor and show that it does not work either.  The
trick is to pass the object being constructed to the constructor.
Your compiler may not accept this, but it is valid.  When the const
object is being constructed, it is not yet const; however, its name
used as a parameter is const.

struct Parent { };
struct Child {
 Child( Child const&, const Parent& m ) : mother( m ) { } // any
 Child( Child&, Parent& m ) : mother( m ) { }  // never for const
 const Parent&   getMother() const { return mother; }
 Parent& getMother() { return (Parent&)mother; }
 const Parent&   mother;
 };
void foo () {
 const Parent mom1;
 Parent mom2;
 const Child child1( child1, mom1 ); // (const, const)
 const Child child2( child2, mom2 ); // P -> P const -> (const, const)
 Child child3( child3, mom2 ); // (nonconst, nonconst)
 Child child4( child4, mom1 ); // C -> C const -> (const, const)
 child1.getMother();  // const get
 child2.getMother();  // const get
 child3.getMother();  // non-const get
 child4.getMother();  // non-const get
 Child child5(child1); // Now what?
 child5.getMother();  // non-const get
 }

Would you also change the rules to say that a copy of a const object
can not be created?  We could likely come up with a kludge for that
also which might prevent pass/return by value.  There must be a way
within the language to accomplish what you want.  But the const ctor
change to the language is not the solution.

John
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: czerwonka@zebra.net (Andy Czerwonka)
Date: 1997/05/20
Raw View
In article <5ljuk6$auf$1@piano.synapse.net>, climate@on.bell.ca says...
> Does the standard preclude defining a constructor as "const"?   I haven't
> found a compiler that allows this but it makes perfect sense to me.  I
> browsed through the ARM looking for info on this but I fell asleep.

Why you would EVER want to have a const ctor is beyond me.  The very
definition of ctor's tells us that these function SET the internal state
of the object.  Before the default ctor call the 'this' pointer is only
valid.  Object that it points to may not be valid until AFTER it's
creation.

--

Cheers,
Andy
---
[ 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: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/20
Raw View
Mike Whiten wrote:
>
>    A const constructor allows me to do the following:
>
>           const Parent     mom1;
>                 Parent     mom2;
>
>           const Child      child1( mom1 );
>           const Child      child2( mom2 );
>                 Child      child3( mom2 );
>
>         //      Child      child4( mom1 );
>                             /* illegal - taking away const'ness */
>
>                 child1.getMother();  // calls const mem func
>                 child2.getMother();  // calls const mem func
>                 child3.getMother();  // calls non-const mem func
>
>    Without the const constructor, only child3 could be created.  If I
>    declare "mother" as being a "const Parent&" in the class definition,
>    I can't create any Child from a non-const Parent& (eg child2 and child3).

You're confusing the constness of the parent pointer with the constness
of the parent itself. Whether a "child" is const or non-const has
nothing to do with whether the parent it points to is const or
non-const. It looks to me like you need two classes, a child that is
allowed to modify its parent, and a child that is not. You could
conceivably have a non-const child that is not allowed to modify its
parent (but whose parent pointer could be modified to point to a
different parent), and a const child that is allowed to modify its
parent (but can't be made to point to a different parent).

--

Ciao,
Paul

(Please remove the "strip_these_words_" prefix from the return
address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/05/20
Raw View
On 20 May 1997 15:10:37 PDT, Mike Whiten wrote:

: : struct C {
: :  void f (int const&) const;
: :  void f (int&);
: :  };
: : void foo () {
: :  int i(5);
: :  C c;
: :  C const cc;
: :  cc.f(i); // int& -> int const& -> f(C const&, int const&)
: :  cc.f(7); // f(C const&, int const&)
: :  c.f(i);  // f(C&, int&)
: :  c.f(7);  // C& -> C const& -> f(C const&, int const&)
: :  }

: Woah!  I started making a point-by-point clarification of my original
: post in response to Mr Potter's post, but I want to comment on this
: code fragment.  (BTW, Mr Potter corrected two errors in my orig post.
: Thank you for your clearly thought out reply.)

: Just what does "int const&" mean?

The same thing as const int&, a reference to a const int.

Consider a const pointer to a const pointer to a const int.  I think
(read right to left)
 int const * const * const p;
is more consistent than
 const int * const * const p;
but they mean the same thing.  Usually, const refers to the thing to
its left; however, when there is nothing to its left it refers to the
thing to its right, with exceptions of course.  There is also the
problem
 typedef int* intPtr;
 const intPtr ipc;
is the same as intPtr const which is int * const not int const * nor
const int *.  In new code, I always put const on the right.  Watching
this group and clc++m, it seems that many people are adopting this
convention.

: I've bound a reference to an r-value
: this way before but I always thought I was hacking the compiler doing it --
: ie. severely non-portable and certainly non-Standard code.

Binding of an rvalue to a reference to const (sometimes called a const
reference) is standard.  And the life time rules when it is a
temporary have caused a bit of fun.

: How can the binding between an identifier and an object (ie. a reference)
: be const or non-const since there are no operations defined for references.
: The ARM itself says that references aren't "first-class" types.

Yep, they pass everything to their referent and cannot be rebound.  So
const reference really does not make sence unless we understand that
it means reference to const thing.

: Is this standard C++?  This seems to me to be too cute by half.

Yep, and maybe it now makes sence.
int& is like int *const
const int& == int const& is like int const *const == const int *const

My appologies for confusing the facts in the notation,
John
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/20
Raw View
: struct C {
:  void f (int const&) const;
:  void f (int&);
:  };
: void foo () {
:  int i(5);
:  C c;
:  C const cc;
:  cc.f(i); // int& -> int const& -> f(C const&, int const&)
:  cc.f(7); // f(C const&, int const&)
:  c.f(i);  // f(C&, int&)
:  c.f(7);  // C& -> C const& -> f(C const&, int const&)
:  }

Woah!  I started making a point-by-point clarification of my original
post in response to Mr Potter's post, but I want to comment on this
code fragment.  (BTW, Mr Potter corrected two errors in my orig post.
Thank you for your clearly thought out reply.)

Just what does "int const&" mean?  I've bound a reference to an r-value
this way before but I always thought I was hacking the compiler doing it --
ie. severely non-portable and certainly non-Standard code.

How can the binding between an identifier and an object (ie. a reference)
be const or non-const since there are no operations defined for references.
The ARM itself says that references aren't "first-class" types.

Is this standard C++?  This seems to me to be too cute by half.

Mike
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/20
Raw View
John Potter (jpotter@falcon.lhup.edu) wrote>
>
> >     Given the following class definition:
>
> >         class Child
> >         {
> >              Child( const Parent& m )
> >         : mother( m )  // illegal
> >       { }
>
> >       Child( Parent& m )
> >         : mother( m ) // ok
> >              { }
> >
> >    public:
> >       const Parent&   getMother() const;
> >       Parent&         getMother();
>
> >    private:
> >       Parent&   mother;
>
> >        };
>
> >     The situation I'm facing is I cannot create a Child instance and
> >     bind it to either const *or* non-const Parent objects.   If I type
> >     "mother" as being "const Parent&"'s then the second constructor
> >     fails.
>
> No it doesn't, it is ok to bind a const& to a non-const object.  But
> the second get then requires a cast.

I stand corrected.  I think what I meant to say is I cannot do what I want,
which is to let this constructor initialize the reference mother without
committing to it being const or non-const.  The problem, of course, isn't
the constructor definition, but that the member "mother" is declared const.

> >     What I'd like it to be able to omit the "const" from the data member
> >     declaration (as shown above) and let the instantiation context
> >     determine if they are const references or not.  A const constructor
> >     would allow this:
>
> If a class has a char* member then a const object has a char* const,
> not a char const*.  You are asking to break a lot of programs.  It is
> quite reasonable for a const object to have references/pointers to
> nonconst objects.  The pointer in the const object can not be changed
> but the object to which it points is changable.

As I understand the current state of C++, references and pointers have
completely different behaviour in this context.  When implementing a
relationship with a pointer, one introduces an intermediate object
(the pointer itself) which can be const or non-const.  When implementing
a relationship with a reference, there is no intermediate object
(accessible through the language) to designate as const or non-const.
If, for example, a class has a "char&" member, then a const instance
of that class will have a "const char&" member.

The const constructor would most definitely *not* break a lot of
programs.

> The syntax would be
>  Child (const Parent& m) const >  mother(m) { }

I stand corrected again! =)

> >     Initialization of the const member would only
> >     be allowed in the initializer list.
>
> >     A const constructor allows me to do the following:
>
> >       const Parent     mom1;
> >           Parent     mom2;
>
> >            const Child      child1( mom1 );
> >            const Child      child2( mom2 );
> >                  Child      child3( mom2 );
>
> Yep
>
> >   //  Child      child4( mom1 );
> >         /* illegal - taking away const'ness */
>
> Nope, it calls the const ctor.

Ok... from where I stand, this is illegal because one cannot bind
a non-const identifier ("child4.mother") to a const object ("mom1").

> Sure you can, again.  Here is an example using another member
> function.
>
> struct C {
>  void f (int const&) const;
>  void f (int&);
>  };

Unless the argument matching rules have changed drastically in the
standard, this is illegal in most usages.  I don't see at what
stage of the argument matching algorithm these two fuction would
differentiate themselves.  The only way I can see this working
is if I explicitly convert an expression to match one over the
other:

     c.f( (const int&) i );  // would call C::f(int const&).  No trivial
        // conversion needed, therefore an exact
        // match.
     c.f( i );               // ambiguous.  In this expression, "i"
        // behaves identically whether it is
        // a reference or the original object

Also in your example a temporary (r-value) is used to initialize
a non-const reference.  This is illegal according to the ARM (8.4.3).
Has this changed with the new rules regarding lifetimes of temporaries?

> You don't like the last one, but that is how it works.  So, let's give
> you your const constructor and show that it does not work either.  The
> trick is to pass the object being constructed to the constructor.
> Your compiler may not accept this, but it is valid.

Use of a partially constructed object is undefined according to the
ARM (12.1) and I assume this is also true in the standard.  Since
this is "undefined" all bets are off as to what we can learn from
such an example.

This is problematic, anyways, since the object being passed (i.e. a second
reference to *this) may undergo conversions (including the trivial
conversions) during the argument matching algorithm.  The "receiver"
object (the "actual" *this) will not.  Introducing the argument
could cause a *different* constructor to be called compared to not
using the self-referential argument.

The most direct way of distinguishing between a const object being
created and a non-const object being created would be to have a
const constructor.   It would hold the same role in argument matching
that the type of *this normally plays (ie. no conversions performed
upon it) but would allow it to be distinguishably overloaded with the
non-const constructor.  The initializer list of such
a constructor would still allow for initializing members and base
classes.  The body of the constructor would not allow assigment to
members.

    class X
    {
      public:
  X() const
    : mem1( 0 ), mem2( 0 )
  {
      mem1 = 42; // illegal... mem1 is const
  }

  X()
    : mem1( 0 ), mem2( 0 )
  {
      mem1 = 42; // ok
  }

     private:
 int   mem1;
 int   mem2;
    };

    const X   obj2;  // calls X::X() const
          X   obj1;  // calls X::X()

> When the const
> object is being constructed, it is not yet const; however, its name
> used as a parameter is const.

Why isn't it "const" while its being constructed?  If the type system
says the object being constructed is "const", it's "const".  Objects
don't acheive const'ness... they have it thrust upon them at birth.

> There must be a way
> within the language to accomplish what you want.  But the const ctor
> change to the language is not the solution.

There is... const_cast<T>.  I think that, while the language may currently
not support "const constructors", there is nothing philosophically wrong
with the idea.  There is, in my opinion, a certain amount of elegance to
them and they are consistent with other features of the language.  I think
the impact of allowing this feature would be minimal on existing code.

Mike
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1997/05/21
Raw View
On 20 May 1997 15:11:15 PDT, Mike Whiten wrote:

: John Potter (jpotter@falcon.lhup.edu) wrote>

: > If a class has a char* member then a const object has a char* const,
: > not a char const*.  You are asking to break a lot of programs.  It is
: > quite reasonable for a const object to have references/pointers to
: > nonconst objects.  The pointer in the const object can not be changed
: > but the object to which it points is changable.

: As I understand the current state of C++, references and pointers have
: completely different behaviour in this context.  When implementing a
: relationship with a pointer, one introduces an intermediate object
: (the pointer itself) which can be const or non-const.  When implementing
: a relationship with a reference, there is no intermediate object
: (accessible through the language) to designate as const or non-const.
: If, for example, a class has a "char&" member, then a const instance
: of that class will have a "const char&" member.

Nope.  If a class has a char* member then a const instance has a char*
const, and if the class has a char& member then a const instance has a
char& const with the const being redundant.

Ok, poor choice of words on my part.  When an object is const, only
const member functions (plus ctor and dtor) may be called.  For a
nonconst function this has the type X * const, the object is changable
but the pointer is not.  For a const member function, this has the
type X const * const (const X * const) neither the object nor the
pointer may be changed.  That is the only difference between a const
and nonconst object.  If an object contains a pointer or reference to
another nonconst object, it is perfectly valid for the const member
function to modify the pointed/referenced object.  It may not change
the value of the pointer (what it points to) and references can not be
rebound anyway (they act like pointer const).

The clasical example is vector which when properly written contains
two operator[] with one const returning a const& to an element of the
nonconst implementation data.  It is perfectly valid C++ to write only
the const operator[] and return a nonconst reference.  It could be
used with both const and nonconst vectors.  That would of course
violate the logical constness of a const vector.

This is the side of const which must be properly coded since const in
C++ means that the bit pattern of the object is not changed.  It says
nothing about bits in any object which may be used to implement (via
pointers or references) the object in question.

The other side is the bits which do not reflect the conceptual value
of the object.  Mutable was introduced to allow changing those bits of
a const object.

: The const constructor would most definitely *not* break a lot of
: programs.

Well, no it would not since it would not be in them; however, if your
concept of constness replaced the current concept, it *would* break a
lot of programs.

: > >     Initialization of the const member would only
: > >     be allowed in the initializer list.
: >
: > >     A const constructor allows me to do the following:
: >
: > >       const Parent     mom1;
: > >           Parent     mom2;
: >
: > >            const Child      child1( mom1 );
: > >            const Child      child2( mom2 );
: > >                  Child      child3( mom2 );
: >
: > Yep
: >
: > >   //  Child      child4( mom1 );
: > >         /* illegal - taking away const'ness */
: >
: > Nope, it calls the const ctor.

: Ok... from where I stand, this is illegal because one cannot bind
: a non-const identifier ("child4.mother") to a const object ("mom1").

Yep, if child4.mother is magically sometimes const and sometimes
nonconst; otherwise, a cast is needed somewhere.  In your example,
child.mother was const.  Not what you wanted, but what I commented
upon.

: > Sure you can, again.  Here is an example using another member
: > function.
: >
: > struct C {
: >  void f (int const&) const;
: >  void f (int&);
: >  };

: Unless the argument matching rules have changed drastically in the
: standard, this is illegal in most usages.  I don't see at what
: stage of the argument matching algorithm these two fuction would
: differentiate themselves.  The only way I can see this working
: is if I explicitly convert an expression to match one over the
: other:

Let's look at the cases.  Rewriting the above as global functions with
the this pointer being a reference (since that is how it works on the
call end) we have

 void f(C const&, int const&)
 void f(C&, int&)

An X may be passed to a X const& but an X const may not be passed to a
X&.  The possibilities:
 C const  int const   matches the first
 C const  int         convert int to int const match first
 C        int const   convert C to C const match first
 C        int         matches the second

There is no way to convert anything to match the second.  The only
viable function is the first in all cases except an exact match of the
second.

: Also in your example a temporary (r-value) is used to initialize
: a non-const reference.  This is illegal according to the ARM (8.4.3).
: Has this changed with the new rules regarding lifetimes of temporaries?

Look again, it was bound to a const reference via conversion.  The
second function was never called with a literal int.  No, things have
not changed with respect to this simple case where there was only one
conversion.  They have changed to add rules for determining the best
set of conversions when there are more possibilities.  I compiled it
with USL cfront 3.0.2 which was the ATT version of the ARM.
Unfortunately, it used an anachronism of creating a temporary for an
rvalue and called the wrong function.  g++ got it right.

: > You don't like the last one, but that is how it works.  So, let's give
: > you your const constructor and show that it does not work either.  The
: > trick is to pass the object being constructed to the constructor.
: > Your compiler may not accept this, but it is valid.

: Use of a partially constructed object is undefined according to the
: ARM (12.1) and I assume this is also true in the standard.  Since
: this is "undefined" all bets are off as to what we can learn from
: such an example.

Please note that the un(not partially)constructed object was not used.
It was passed by reference to the constructor which did not even have
a name for it.  Taking the address of an unconstructed object is
certainly valid (how did it get this) which is the same as obtaining a
reference.  The sole use was to determine which constructor to call.

: This is problematic, anyways, since the object being passed (i.e. a second
: reference to *this) may undergo conversions (including the trivial
: conversions) during the argument matching algorithm.

Nope, it is being passed by reference.  The constness can be increased
but the object is not involved.  This was also compiled.  Cfront
messed up some things and g++ didn't understand that the name of an
object exists as soon as it is mentioned.  Xlc compiled it and
executed as expected.

: The "receiver"
: object (the "actual" *this) will not.  Introducing the argument
: could cause a *different* constructor to be called compared to not
: using the self-referential argument.

Nope, again it is a reference not something which can change.  This
can also be converted to const as demonstrated above.  You need to
totally change the rules to get the behavior you desire.

: The most direct way of distinguishing between a const object being
: created and a non-const object being created would be to have a
: const constructor.   It would hold the same role in argument matching
: that the type of *this normally plays (ie. no conversions performed
: upon it)

We do not need a conversion on *it* to call a const member function
with a nonconst object.

: > When the const
: > object is being constructed, it is not yet const; however, its name
: > used as a parameter is const.

: Why isn't it "const" while its being constructed?  If the type system
: says the object being constructed is "const", it's "const".  Objects
: don't acheive const'ness... they have it thrust upon them at birth.

Yep; however, object lifetime starts upon return of the constructor.
How can an object be *born* before it is constructed?  Also note that
an object's lifetime ends upon entry into the destructor where it is
no longer const.

If you do not understand the language, it is no big deal, I do not
claim to understand it either.  And with the current state of
compilers and the moving almost standard there is little way to test
ones understanding.  Perhaps a copy of CD2 (1996) (available, see the
FAC) would be more useful than the ARM (1990).

I doubt that with this much said, I have not got something wrong.
But, I am sure that there are those here who will correct it.

HTH,
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         ]
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/21
Raw View
: >    Without the const constructor, only child3 could be created.  If I
: >    declare "mother" as being a "const Parent&" in the class definition,
: >    I can't create any Child from a non-const Parent& (eg child2 and child3).

: You're confusing the constness of the parent pointer with the constness
: of the parent itself. Whether a "child" is const or non-const has
: nothing to do with whether the parent it points to is const or
: non-const.

There were no pointers in the example I gave (except "this").  What you say
is true... except for the "You're confused..." part.  However, if I have a
class with references:

     struct X;
     struct Y
     {
  X&      mem;
     };

Then a const instance

     const Y     obj;

has a const member "obj.mem".  A non-const instance

    Y     obj2;

has a non-const member "obn2.mem".
---
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/21
Raw View
John Potter (jpotter@falcon.lhup.edu) wrote:
: On 20 May 1997 15:10:37 PDT, Mike Whiten wrote:

: My appologies for confusing the facts in the notation,


Thanks for the insight.  It occured to me what you meant as I re-read
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: dHarrison@worldnet.att.net (Doug Harrison)
Date: 1997/05/22
Raw View
On 21 May 97 14:22:03 GMT, climate@on.bell.ca (Mike Whiten) wrote:

>There were no pointers in the example I gave (except "this").  What you say
>is true... except for the "You're confused..." part.  However, if I have a
>class with references:
>
>     struct X;
>     struct Y
>     {
>  X&      mem;
>     };
>
>Then a const instance
>
>     const Y     obj;
>
>has a const member "obj.mem".  A non-const instance

But the type of obj's mem is not "const X&", it is still X&. If a
reference was an object, I'd agree with you and say that the type of
obj's mem is "X& const", but that isn't really correct. References
aren't objects, the type "X& const" doesn't exist, and the type of
obj's mem is just X&.

>    Y     obj2;
>
>has a non-const member "obn2.mem".

As I understand it, and given that a non-const reference member
doesn't become a reference-to-const in a const object, your const ctor
suggestion would allow one to perform a const_cast without saying
const_cast:

 struct A
 {
    // Implicit loss of const here...
    A(const X& x) const : m_x(x) {}
    X& m_x;
 };

 const X x;
 const A a(x);

Now assume A has a const member function:

 void A::fun() const { m_x.CallNonConstFunction(); }
 a.fun();

or simply:

 a.m_x.CallNonConstFunction();

The above is perfectly fine, because m_x isn't a reference to const,
even when it belongs to a const A. Fortunately, C++ requires a
const_cast to subvert the type system as shown above.

--
Doug Harrison
dHarrison@worldnet.att.net
---
[ 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: "Paul D. DeRocco" <pderocco@strip_these_words.ix.netcom.com>
Date: 1997/05/22
Raw View
John Potter wrote:
>
> Ok, poor choice of words on my part.  When an object is const, only
> const member functions (plus ctor and dtor) may be called.  For a
> nonconst function this has the type X * const, the object is changable
> but the pointer is not.  For a const member function, this has the
> type X const * const (const X * const) neither the object nor the
> pointer may be changed.  That is the only difference between a const
> and nonconst object.  If an object contains a pointer or reference to
> another nonconst object, it is perfectly valid for the const member
> function to modify the pointed/referenced object.  It may not change
> the value of the pointer (what it points to) and references can not be
> rebound anyway (they act like pointer const).

You and Mike seem to disagree on the interpretation of a non-const
reference within a const structure:

 struct foo {
     int value:
     int& target;
     foo(int v, int& t): value(v), target(t) {}
     };

 int a_value = 0;
 int a_target = 0;
 const foo a_foo(a_value, a_target);

 void test() {
     a_foo.value = 1; // not legal
     a_foo.target = 1; // legal?
     }

I can't set a_foo.value, because a_foo is const, right? But does the
constness of a_foo prevent me from setting a_foo.target, even though it
is a non-const reference? That is the question.

--

Ciao,
Paul

(Please remove the "strip_these_words." prefix from the return
address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/17
Raw View
Does the standard preclude defining a constructor as "const"?   I haven't
found a compiler that allows this but it makes perfect sense to me.  I
browsed through the ARM looking for info on this but I fell asleep.

Mike Whiten
mw@synapse.net
---
[ 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: "Edmund Robinson" <ebrobins@ibl.bm>
Date: 1997/05/18
Raw View
To my knowledge const member functions can not modify data members.
That means a const constructor would not be able to set the values of the
class object.  A const constructor is an oxymoron

Mike Whiten <climate@on.bell.ca> wrote in article
<5ljuk6$auf$1@piano.synapse.net>...
> Does the standard preclude defining a constructor as "const"?   I haven't
> found a compiler that allows this but it makes perfect sense to me.  I
> browsed through the ARM looking for info on this but I fell asleep.
---
[ 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: climate@on.bell.ca (Mike Whiten)
Date: 1997/05/19
Raw View
Edmund Robinson (ebrobins@ibl.bm) wrote:
: To my knowledge const member functions can not modify data members.
: That means a const constructor would not be able to set the values of the
: class object.  A const constructor is an oxymoron

const object can, however, be written to at initialization.  Example:

 const int        i = 5;        // writes to const object
 const Complex    c(0.0, 0.0);  // writes to const object

I don't see any reason to preclude initialization of known const members
since you can initialize const objects in other contexts.

I'll briefly summarize why I think this should be allowed:

   Given the following class definition:

       class Child
       {
            Child( const Parent& m )
       : mother( m )  // illegal
     { }

     Child( Parent& m )
       : mother( m ) // ok
            { }

  public:
     const Parent&   getMother() const;
     Parent&         getMother();

  private:
     Parent&   mother;

      };

   The situation I'm facing is I cannot create a Child instance and
   bind it to either const *or* non-const Parent objects.   If I type
   "mother" as being "const Parent&"'s then the second constructor fails.

   What I'd like it to be able to omit the "const" from the data member
   declaration (as shown above) and let the instantiation context
   determine if they are const references or not.  A const constructor
   would allow this:

  Child( const Parent& m )
    : mother( m ) const
  { }

   since the const implies that "this" is of type "const Child*", the
   data member, "mother", is const.  The binding of the references is
   still legal, because one can always initialize const object
   identifiers.  This constructor would only be invoked when initializing
   a const Child object.  Initialization of the const member would only
   be allowed in the initializer list.

   A const constructor allows me to do the following:

   const Parent     mom1;
  Parent     mom2;

          const Child      child1( mom1 );
   const Child      child2( mom2 );
  Child      child3( mom2 );

 //  Child      child4( mom1 );
       /* illegal - taking away const'ness */

  child1.getMother();  // calls const mem func
  child2.getMother();  // calls const mem func
  child3.getMother();  // calls non-const mem func

   Without the const constructor, only child3 could be created.  If I
   declare "mother" as being a "const Parent&" in the class definition,
   I can't create any Child from a non-const Parent& (eg child2 and child3).


Regards,
Mike


PS.  Ignore my "return" address ... it's incorrect in the header.  Send
     replies to "mw@synapse.net"
---
[ 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                             ]