🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #3797

constness of private members and methods

#3797
From: Philippe Verdy
Date: Mon, 25 Mar 1996 18:04
105 lines
4836 bytes
Many recursive data structures require algorithms to handle
them which have to mark and unmark all scanned objects in
order to avoid infinite recursion when walking on that
structure, or when building items iterator.
Such algorithms will use the mark() and unmark() private
methods in each visited node, so that we can detect paths
which have already been visited. his is critical for example
when managing with auto-references, graphs, dictionnaries
of polymorphic objects (containing dictionnaries like in
a PostScript interpret).
However, how can we apply standard read-only methods on such
objects: these methods are specified as const in one of the
base classes, and virtual override requires not to change the
constness of the derived object.
So we cannot mark such structures, because even a private
member cannot be modified in a const instance.
We can effectively change temporarily the constness of the
object to realize this mark, but in that case we would write
the following :
  class T {
  public:
    T()                   { ...; _mark = 0; }
    virtual ~T();

    virtual void show() const;
  protected:
    void mark()           { _mark = 1; }
    void unmark()         { _mark = 0; }
    bool ismarked() const { return _mark; }
  private:
    char _mark;
  }
The problem is that now mark() and unmark() methods are not
const so they cannot be used in read-only methods like show().
So we have to use a const_cast<T&> or const_cast<T*> to
suppress this constness.

This is not obvious, and has the big disadvantage of globally
suppressing the constness of the object. So this is quite
dangerous, because some-times, we do not know really if a
method has an impact on the semantic value of the instance
on which we apply this cast. So this is a security hole which
should be avoided.

We can avoid const_casting to call mark() and unmark() by
declaring them as const, like this:
  protected:
    void mark() const   { (const_cast<T*>this)->_mark = 1; }
    void unmark() const { (const_cast<T*>this)->_mark = 0; }
but this is really hard to write, and is it semantically
correct ? It would from the public point of view, but what
on the private point of view ?

We can also use explicitly (const_cast<T*>this)->mark(); and
(const_cast<T*>this)->unmark(); calls in the show()
implementation, but this is quite hard to write, so that many
users refrain using const specifiers on their classes.

Is there any way (or proposal) to explicitly specify members
of a class definition which are relaxed on constness certi-
fication ?

Would not it be great if we could simply define such members
as "unconst" like in the following example :

  class T {
  public:
    T()                   { ...; _mark = 0; }
    virtual ~T();

    virtual void show() const;
  protected:
    void mark() const     { _mark = 1; } // RELAXED HERE
    void unmark() const   { _mark = 0; } // RELAXED HERE
    bool ismarked() const { return _mark; }
  private:
    unconst char _mark; // HERE IS WHERE THIS APPLIES
  }

In that example, even thow the mark() and unmark() methods
are const-specified, we are allowed to modify the _mark
member, because it has been explicitly relaxed.

We could restrict the unconst modifier usage to private
or protected members declaration only, so that the public
interface of a class would keep the constness integrity.

This way, the dangerous const_cast<> operator could be avoided
most of the time and isolated in specific class
implementations (for compatibility with not const-compliant
C libraries)...

What do you think ?

And is constness definition a semantic only definition,
or does it involve a more strict sense in which the compiler
optimizer would have an influence (such as in common
subexpressions reduction) ?
---
[ 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 
]
Technical Details
Message-ID: <4j49e0$8fo@dub-news-svc-4.compuserve.com>
Path: arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austern

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austern
From: Philippe Verdy <100105.3120@compuserve.com>
Newsgroups: comp.std.c++
Subject: constness of private members and methods
Date: 25 Mar 1996 10:04:56 PST
Organization: CompuServe Incorporated
Approved: austern@isolde.mti.sgi.com
Message-ID: <4j49e0$8fo@dub-news-svc-4.compuserve.com>
NNTP-Posting-Host: isolde.mti.sgi.com
X-Original-Date: 24 Mar 1996 19:56:48 GMT
X-Auth: PGPMoose V1.1 PGP comp.std.c++
 iQBVAwUBMVbgV0y4NqrwXLNJAQFmJQH/WLQML6cwTrsQ7ff4Ill7GUEKrP/5hjog
 QP9gzv3KSMjbkVEL1oCxfrb+uj9E8o9kobAJQkYRF7KKOHppoVe7rA==
 =Mt3Q
Originator: austern@isolde.mti.sgi.com