Thread View: comp.std.c++
6 messages
6 total messages
Started by Philippe Verdy
Mon, 25 Mar 1996 18:04
constness of private members and methods
Author: Philippe Verdy
Date: Mon, 25 Mar 1996 18:04
Date: Mon, 25 Mar 1996 18:04
105 lines
4836 bytes
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
]
Re: constness of private members and methods
Author: Steve Clamage
Date: Tue, 26 Mar 1996 00:29
Date: Tue, 26 Mar 1996 00:29
24 lines
1491 bytes
1491 bytes
In article 8fo@dub-news-svc-4.compuserve.com, Philippe Verdy >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 : The C++ draft standard has for some time included the keyword "mutable". A mutable data member may be modified by any member function, even if the object or the member function is const. --- Steve Clamage, stephen.clamage@eng.sun.com [ 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 ]
Re: constness of private members and methods
Author: Dietmar Kuehl
Date: Tue, 26 Mar 1996 04:46
Date: Tue, 26 Mar 1996 04:46
53 lines
2991 bytes
2991 bytes
Hi,
Philippe Verdy (100105.3120@compuserve.com) wrote:
[lengthy description of problems with bitwise instead of logical
constness elided]
: Is there any way (or proposal) to explicitly specify members
: of a class definition which are relaxed on constness certi-
: fication ?
Yes: it is possible to declare a data member of an object to be
'mutable'. This allows to modify this member even in a 'const'
function. The main idea which leads to a reasonable use of 'mutable' is
the concept of logical versus bitwise constness: In C++ bitwise
constness is generally assumed. You cannot change the member of a
constant object. However, sometimes this is not what you want (auxilary
marks and cached values are two examples). Instead, logical constness
is desired: The representation of the object might change but the value
represented stays the same. Note, however, that the language does not
(and can not) enforce that logical constness is maintained if the
object has mutable members. It is the responsibility of the programmer
to ensure logical constness.
: 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
: }
If you replace 'unconst' by 'mutable' you have what will become
standard. Since the 'mutable' keyword is a recent addition to the
DWP, it is not yet supported by all compilers.
--
dietmar.kuehl@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic
---
[ 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 ]
Re: constness of private members and methods
Author: Rob Stewart
Date: Tue, 26 Mar 1996 06:55
Date: Tue, 26 Mar 1996 06:55
116 lines
6494 bytes
6494 bytes
Philippe Verdy wrote: > > 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 :[snip] > 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:[snip] > 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. > [snip] > 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) ? There are two schools of thought regarding const-ness. One requires strict bitwise constness. That means that if you construct a const object, did a memcpy of the object to some suitable buffer, exercised the object using any permissible (const) mfs, in any combination, then compared the object with the memcpy'd buffer, there would be no change. The other requires only logical constness. That means that the object always appears the same through its public and protected interfaces. You can do what you want inside the object, provided it always appears the same to the class user. The compiler obviously enforces the former definition. You must cast away constness when you want the latter. That definition is the one you're employing here. According to how you've described mark and unmark, they must be controlled by other functions such that the original state is restored before return to the caller. That is, some other function must use mark and unmark, in matched sets for each node, in order to preserve the external state of the object. Therefore, it is not mark and unmark which should cast away constness, but those functions that make use of them. mark and unmark should be non-const; they each change the state in a way that affects the external state of the class. Those functions calling them must cast away constness to use them. As for your question about some language extension to permit that behavior, it could only apply to functions calling mark and unmark in their use of them. That is, since only functions using mark and unmark can ensure that the original state is restored--thus preserving the logical constness--only they can be used on const objects. Therefore, they should be the ones to get special dispensation to use non-const mfs in such a way that they retain logical constness. The difficulty is with maintenance. Sure, after some design and debugging work, you can get the functions to work correctly such that you retain logical constness. The maintainer of your code may have more trouble or may not realize the consequence of his actions, and destroy logical constness. Once you violate the bitwise constness of the compiler, you're on your own. This is true of casting away constness yourself, but would we really want a language feature which makes it easy and makes less clear where special attention is required? I don't think so. Instead, you should consider how to build a base class that encapsulates the iteration process to which you can pass a derived class mf to process each node you encounter. The implementation will appear once in your code and shouldn't require maintenance once you fix the bugs. All the rest of your code that needs to iterate the container will make use of that base class functionality, but won't need to worry about casting away constness. -- Robert Stewart | My opinions are usually my own. Datalytics, Inc. | stew@datalytics.com --- [ 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 ]
Re: constness of private members and methods
Author: Andrew Bell
Date: Tue, 26 Mar 1996 07:19
Date: Tue, 26 Mar 1996 07:19
36 lines
2290 bytes
2290 bytes
Philippe Verdy <100105.3120@compuserve.com> wrote: >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. The property of being marked is really part of your algorithm, not part of the object itself. You should consider making some sort of separate record (a list of some sort) to indicate which items are marked and unmarked. Otherwise, you'll then find an algorithm where you have to mark things twice, and so on... >Is there any way (or proposal) to explicitly specify members >of a class definition which are relaxed on constness certi- >fication ? Sounds like "mutable" to me. >And is constness definition a semantic only definition, Being const means only that the current function won't change the object, not that the object itself won't change during the function. It could change as the result of a side effect of another function called within the current one. Thus unless only inline or other internally known functions are called, no additional optimizations are possible. Andrew Bell abell@mindspring.com --- [ 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 ]
Re: constness of private members and methods
Author: James Kanze US/ESC 60/3/141 #407...
Date: Tue, 26 Mar 1996 16:22
Date: Tue, 26 Mar 1996 16:22
34 lines
2064 bytes
2064 bytes
In article <4j49e0$8fo@dub-news-svc-4.compuserve.com> Philippe Verdy
<100105.3120@compuserve.com> writes:
|> 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
|> }
You can. Except that `unconst' is spelled `mutable'.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, études et réalisations en logiciel orienté objet --
-- A la recherche d'une activité dans une region francophone
[ 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 ]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads